diff options
Diffstat (limited to 'files/vi/learn/server-side/express_nodejs/mongoose/index.html')
-rw-r--r-- | files/vi/learn/server-side/express_nodejs/mongoose/index.html | 800 |
1 files changed, 0 insertions, 800 deletions
diff --git a/files/vi/learn/server-side/express_nodejs/mongoose/index.html b/files/vi/learn/server-side/express_nodejs/mongoose/index.html deleted file mode 100644 index fdf6531d75..0000000000 --- a/files/vi/learn/server-side/express_nodejs/mongoose/index.html +++ /dev/null @@ -1,800 +0,0 @@ ---- -title: 'Hướng dẫn Express Phần 3: Sử dụng Database (với Mongoose)' -slug: Learn/Server-side/Express_Nodejs/mongoose -translation_of: Learn/Server-side/Express_Nodejs/mongoose ---- -<div>{{LearnSidebar}}</div> - -<div>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</div> - -<p class="summary">Bài viết này giới thiệu tổng quan về cơ sở dữ liệu và cách dùng chúng với các ứng dụng Node/Express. Sau đó nó sẽ chỉ cho ta thấy cách sử dụng <a href="http://mongoosejs.com/">Mongoose</a> để tạo ra kết nối đến cơ sở dữ liệu cho trang web <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>. Nó giải thích cách mà schema và model của đối tượng được định nghĩa, các kiểu trường chính, và cách thức xác thực cơ bản. Nó còn trình bày một số cách chính để bạn có thể truy cập tới dữ liệu của model.</p> - -<table class="learn-box standard-table"> - <tbody> - <tr> - <th scope="row">Bài viết trước:</th> - <td><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></td> - </tr> - <tr> - <th scope="row">Mục tiêu:</th> - <td>Có thể thiết kế và tự tạo model của riêng mình thông qua Mongoose.</td> - </tr> - </tbody> -</table> - -<h2 id="Khái_quát">Khái quát</h2> - -<p>Thủ thư sẽ dùng trang web Local Library để lưu trữ thông tin về sách và người mượn, trong khi các bạn đọc sẽ dùng nó để kiếm sách, tìm xem có bao nhiêu cuốn có sẵn, và tiếp tục như thế hoặc làm thủ tục mượn sách. Để có thể lưu trữ và truy xuất thông tin một cách hiệu quả, ta sẽ lưu trữ tất cả trong một <em>cơ sở dữ liệu</em>.</p> - -<p>Các ứng dụng Express có thể dùng nhiều loại cơ sở dữ liệu khác nhau, và có khá là nhiều hướng tiếp cận để bạn có thể thi hành <strong>C</strong>reate, <strong>R</strong>ead, <strong>U</strong>pdate and <strong>D</strong>elete (CRUD). Bài viết này sẽ cung cấp khái quát một số lựa chọn có thể áp dụng, và sẽ đi vào phân tích một phương pháp nhất định.</p> - -<h3 id="Tôi_có_thể_dùng_cơ_sở_dữ_liệu_nào">Tôi có thể dùng cơ sở dữ liệu nào?</h3> - -<p>Ứng dụng<em> Express</em> có thể dùng bất cứ cơ sở dữ liệu nào được hỗ trợ bởi <em>Node</em> (Chính <em>Express</em> không đưa ra bất cứ đặc tả chỉ tiết hành vi hay ràng buộc nào về hệ quản trị cơ sở dữ liệu). Thành ra có <a href="https://expressjs.com/en/guide/database-integration.html">rất nhiều thứ</a> để bạn thoả sức chọn lựa, bao gồm PostgreSQL, MySQL, Redis, SQLite, và MongoDB.</p> - -<p>Khi chọn một cơ sở dữ liệu, bạn nên cân nhắc những thứ như là độ khó, hiệu năng, dễ dàng bảo trì, chi phí, sự hỗ trợ của cộng đồng, vân vân và mây mây. Do chưa có cơ sở dữ liệu nào đạt được danh hiệu 'tốt nhất', nên ta có thể lựa chọn hầu như mọi giải pháp vừa kể trên cho một trang cỡ nhỏ tới vừa như trang Local Library của chúng ta.</p> - -<p>Để biết thêm chi tiết để tiện đường lựa chọn: <a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (Tài liệu của Express).</p> - -<h3 id="Cách_nào_tốt_nhất_để_thao_tác_với_cơ_sở_dữ_liệu">Cách nào tốt nhất để thao tác với cơ sở dữ liệu?</h3> - -<p>Có hai hướng tiếp cận để tương tác với một cơ sở dữ liệu: </p> - -<ul> - <li>Sử dụng ngôn ngữ truy vấn của riêng cơ sở dữ liệu đó (ví dụ như SQL)</li> - <li>Sử dụng Object Data Model ("ODM") / Object Relational Model ("ORM"). ODM/ORM đại diện cho dữ liệu của trang web dưới dạng đối tượng trong JavaScript, sau đó ánh xạ tới cơ sở dữ liệu bên dưới. Một vài ORMs được gắn với một cơ sở dữ liệu nào đó, trong khi số khác chỉ là một cầu nối giữa cơ sở dữ liệu và phần code backend.</li> -</ul> - -<p>Sử dụng ngôn ngữ truy vấn được hỗ trợ bởi cơ sở dữ liệu (như là SQL) sẽ đạt được <em>hiệu suất</em> cao nhất. ODM thường chậm hơn bởi nó phải thông dịch mã để có thể truy vấn giữa đối tượng và định dạng của cơ sở dữ liệu, mà không dùng được các truy vấn hiệu quả nhất của cơ sở dữ liệu (điều này càng nghiêm trọng hơn khi ORM được sử dụng cho nhiều dạng cơ sở dữ liệu khác nhau, và phải tạo ra nhiều điều khoản lằng nhằng hơn đối với lượng tính năng được cơ sở dữ liệu hỗ trợ).</p> - -<p>Điểm mạnh của ORM là lập trình viên có thể giữ tư duy như với đối tượng của JavaScript thay vì phải ngôn ngữ thuần tuý viết riêng cho cơ sở dữ liệu — điều này càng đúng khi bạn phải làm việc với nhiều loại cơ sở dữ liệu (trên cùng hoặc khác trang web). ORM còn cung cấp các tính năng để thực hiện xác thực và kiểm tra dữ liệu.</p> - -<div class="note"> -<p><strong>Mẹo:</strong> Sử dụng ODM/ORMs thường giúp giảm thiểu chi phí phát triển và bảo trì! Trừ khi bạn đã quá thân thuộc với ngôn ngữ truy vấn thuần tuý hoặc hiệu suất là trên hết, bạn nên cân nhắc đến việc sử dụng ODM.</p> -</div> - -<h3 id="Tôi_nên_dùng_ORMODM_nào">Tôi nên dùng ORM/ODM nào?</h3> - -<p>Có nhiều giải pháp cho ODM/ORM có sẵn trên trang quản lý gói NPM (tìm theo nhãn <a href="https://www.npmjs.com/browse/keyword/odm">odm</a> và <a href="https://www.npmjs.com/browse/keyword/orm">orm</a>!).</p> - -<p>Vào thời điểm viết bài này có một số giải pháp phổ biến như sau:</p> - -<ul> - <li><a href="https://www.npmjs.com/package/mongoose">Mongoose</a>: Mongoose là một công cụ mô hình hoá đối tượng <a href="https://www.mongodb.org/">MongoDB</a>, được thiết kế để làm việc trên môi trường bất đồng bộ.</li> - <li><a href="https://www.npmjs.com/package/waterline">Waterline</a>: Một ORM trích xuất từ <a href="http://sailsjs.com/">Sails</a> framework, có nền tảng là Express. Nó cung cấp một bộ API tiêu chuẩn để truy cập vào vô số kiểu cơ sở dữ liệu khác nhau, bao gồm Redis, mySQL, LDAP, MongoDB, và Postgres.</li> - <li><a href="https://www.npmjs.com/package/bookshelf">Bookshelf</a>: Trên nền promise và giao diện callback truyền thống, cung cấp hỗ trợ transaction, eager/nested-eager relation loading, sự kết hợp đa hình, and hỗ trợ quan hệ một-một, một-nhiều, nhiều-nhiều. Làm việc với PostgreSQL, MySQL, và SQLite3.</li> - <li><a href="https://www.npmjs.com/package/objection">Objection</a>: Vận dụng hết sức mạnh của SQL và hạ tầng cơ sở dữ liệu bên dưới (hỗ trợ SQLite3, Postgres, và MySQL) theo cách dễ dàng nhất có thể.</li> - <li> - <p><a href="https://www.npmjs.com/package/sequelize">Sequelize</a> là một ORM nền Promise dành cho Node.js và io.js. Nó hỗ trợ biên dịch PostgreSQL, MySQL, MariaDB, SQLite và MSSQL và hỗ trợ giao tác cứng, các quan hệ, read replication và nhiều hơn thế.</p> - </li> - <li> - <p><a href="https://node-orm.readthedocs.io/en/latest/">Node ORM2 </a>là Trình quản lý mối quan hệ đối tượng cho NodeJS. Nó hỗ trợ MySQL, SQLite và Progress, giúp làm việc với cơ sở dữ liệu bằng cách sử dụng phương pháp hướng đối tượng.</p> - </li> - <li> - <p><a href="http://1602.github.io/jugglingdb/">JugglingDB </a>là ORM DB chéo cho NodeJS, cung cấp giao diện chung để truy cập hầu hết các định dạng cơ sở dữ liệu phổ biến. Hiện đang hỗ trợ MySQL, SQLite3, Postgres, MongoDB, Redis và js-memory-Storage (công cụ tự viết để chỉ sử dụng thử nghiệm).</p> - </li> -</ul> - -<p>Như một luật ngầm định, bạn nên cân nhắc cả tính năng được công bố cũng như "hoạt động cộng đồng" (tải xuống, sự đóng góp, báo lỗi, chất lượng của tài liệu, vân vân và mây mây) khi lựa chọn một giải pháp. Vào thời điểm viết bài thì Mongoose là một ORM phổ biến nhất, và là lựa chọn hợp lý nếu bạn dùng MongoDB làm cơ sở dữ liệu của mình.</p> - -<h3 id="Sử_dụng_Mongoose_và_MongoDb_cho_LocalLibrary">Sử dụng Mongoose và MongoDb cho LocalLibrary</h3> - -<p>Đối với ví dụ <em>Local Library</em> (và cho cả phần còn lại của bài viết này) ta sẽ sử dụng <a href="https://www.npmjs.com/package/mongoose">Mongoose ODM</a> để truy cập dữ liệu thư viện của chúng ta. Mongoose hoạt động như một frontend của <a href="https://www.mongodb.com/what-is-mongodb">MongoDB</a>, cơ sở dữ liệu mở dạng <a href="https://en.wikipedia.org/wiki/NoSQL">NoSQL</a> sử dụng mô hình dữ liệu hướng document. Một “collection” và “documents”, trong cơ sở dữ liệu MongoDB, <a href="https://docs.mongodb.com/manual/core/databases-and-collections/#collections">tương tự với</a> một “table” và “row” trong cơ sở dữ liệu quan hệ.</p> - -<p>ODM và kết hợp cơ sở dữ liệu này cực kì phổ biến trong cộng đồng Node, phần lớn là bởi kho chứa document và hệ thống truy vấn khá là giống với JSON, vã dĩ nhiên rất đỗi thân quen với các lập trình viên JavaScript.</p> - -<div class="note"> -<p><strong>Mẹo:</strong> Bạn không cần phải biết gì về MongoDB để có thể sử dụng được Mongoose, mặc dù vài phần trong <a href="http://mongoosejs.com/docs/guide.html">tài liệu của Mongoose</a> <em>sẽ</em> dễ đọc hiểu hơn nếu bạn đã quen với MongoDB rồi.</p> -</div> - -<p>Phần còn lại của bài viết này hướng dẫn cách để định nghĩa và truy cập schema và model của Mongoose thông qua ví dụ làm trang web cho <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">LocalLibrary</a>.</p> - -<h2 id="Thiết_kế_model_LocalLibrary">Thiết kế model LocalLibrary</h2> - -<p>Trước khi nhảy bổ vào viết code cho model, sẽ tốt hơn nếu ta dành vài phút để nghĩ về dữ liệu ta cần phải lưu trữ và mối quan hệ giữa các đối tượng khác nhau.</p> - -<p>Chúng ta biết rằng chúng ta cần phải lữu trữ dữ liệu về sách (tựa đề, tóm tắt, tác giả, thể loại, mã số tiêu chuẩn quốc tế cho sách) và sẽ có khá nhiều cuốn giống nhau (với mã số quốc tế riêng biệt, tình trạng, vân vân.). Có lẽ ta sẽ cần lưu trữ nhiều thông tin về tác giả hơn chỉ là tên của người đó, và có vô số tác giả trùng hoặc có tên na ná nhau. Chúng ta muốn phân loại thông tin dựa theo tựa đề, tác giả, thể loại, và kiểu sách.</p> - -<p>Công cuộc thiết kế model yêu cầu thiết kế các mô hình riêng rẽ cho từng "object" (nhóm các thông tin có liên quan với nhau). Trong trường hợp này thì các object ấy hẳn là sách, các thuộc tính của sách, và tác giả.</p> - -<p>Bạn chắc hẳn sẽ muốn biểu diễn mô hình dưới dạng danh sách liệt kê (ví dụ như một danh sách các lựa chọn), thay vì code cứng tất tần tật — việc này được đề nghị khi các lựa chọn vẫn chưa được liệt kê hết hoặc có thể bị thay đổi. Ứng viên sáng giá cho việc mô hình hoá này chính là thể loại sách (ví dụ như Khoa học Viễn tưởng, Ngôn tình, hoặc gì đó tương tự.)</p> - -<p>Khi đã quyết định được các mô hình và trường dữ liệu, ta cần phải suy ngẫm về mối quan hệ giữa chúng.</p> - -<p>Để làm tốt việc này, ta sẽ dùng biểu đồ liên hệ UML như bên dưới để biểu diễn các model ta sắp định nghĩa ra (trong các hộp). Như đã nói ở trên, ta vừa tạo ra model cho sách (chi tiết cơ bản nhất cho sách), phần tử của sách (lượng bản sách còn trong hệ thống), và tác giả. Chúng ta cũng vừa quyết định sẽ tạo thêm model cho thể loại, để giá trị của nó thay đổi động. Ta cũng vừa quyết định sẽ không tạo mô hình cho <code>BookInstance:status</code> — chúng ta sẽ code cứng phần này đến một giá trị có thể chấp nhận được bởi ta không mong muốn giá trị của nó bị thay đổi. Bạn có thể thấy trong mỗi hộp là tên của mô hình, tên của các trường và kiểu dữ liệu tương ứng, đồng thời cả các thuộc tính và kiểu trả về nữa.</p> - -<p>Biểu đồ còn chỉ ra mối quan hệ giữa các mô hình, bao gồm cả <em>bội số</em>. Bội số là các con số nhỏ nhỏ nằm trên các đường thẳng nối các hộp lại với nhau (lớn nhất và nhỏ nhất) để chỉ ra độ liên hệ trong các mối quan hệ giữa các mô hình với nhau. Láy ví dụ như trong hình dưới, những đoạn kẻ nối giữa các hộp biểu diễn rằng <code>Book</code> và <code>Genre</code> liên quan đến nhau. Con số nằm gần với mô hình <code>Book</code> chỉ ra rằng Book phải có từ 0 đến nhiều <code>Genre</code> (bao nhiêu tuỳ thích), trong khi con số nằm ở đầu đoạn bên kia của <code>Genre</code> lại chỉ ra rằng nó có 0 hoặc nhiều liên hệ với Book.</p> - -<div class="note"> -<p><strong>Lưu ý</strong>: Như đã nói trong <a href="#related_documents">Mongoose primer</a> phía dưới, thường sẽ tốt hơn nếu có một trường riêng để định nghĩa mối quan hệ giữa documents/models chỉ trong <em>một</em> mô hình (bạn vẫn có thể tìm thấy mối quan hệ ngược lại bằng cách tìm kiếm <code>_id</code> liên quan trong các mô hình khác). Bên dưới biểu diễn mối quan hệ giữa Book/Genre and Book/Author trong Book schema, và mối quan hệ giữa Book/BookInstance trong BookInstance Schema. Việc lựa chọn này hơi cảm tính — ta hoàn toàn có thể định nghĩa các trường trong một schema khác.</p> -</div> - -<p><img alt="Mongoose Library Model with correct cardinality" src="https://mdn.mozillademos.org/files/15645/Library%20Website%20-%20Mongoose_Express.png" style="height: 620px; width: 737px;"></p> - -<div class="note"> -<p><strong>Lưu ý</strong>: Phần tiếp theo cung cấp kiến thức cơ bản giải thích cách mô hình được định nghĩa và sử dụng. Ta sẽ tìm cách để xây dựng đống mô hình vừa vẽ ra trong biểu đồ trên.</p> -</div> - -<h2 id="Mongoose_primer">Mongoose primer</h2> - -<p>Phần này giới thiệu khái quát cách để kết nối Mongoose với một cơ sở dữ liệu MongoDB, cách định nghĩa một schema và một model, và cách viết vài câu truy vấn đơn giản. </p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Cái primer này "bị ảnh hưởng mạnh" bởi <a href="https://www.npmjs.com/package/mongoose">Mongoose quick start</a> trên <em>npm</em> và <a href="http://mongoosejs.com/docs/guide.html">official documentation</a>.</p> -</div> - -<h3 id="Cài_đặt_Mongoose_và_MongoDB">Cài đặt Mongoose và MongoDB</h3> - -<p>Mongoose được cài đặt vào trong project của bạn (<strong>package.json</strong>) giống hệt như các dependency khác — dùng NPM. Để cài đặt nó, chạy câu lệnh sau trong thư mục project của bạn:</p> - -<pre class="brush: bash"><code>npm install mongoose</code> -</pre> - -<p>Sau khi cài xong, <em>Mongoose</em> sẽ tự động thêm mọi dependencies của nó, bao gồm cả driver cơ sở dữ liệu cho MongoDB, nhưng nó sẽ không cài đặt MongoDB đâu nhé. Nếu bạn muốn cài đặt một máy chủ MongoDB thì bạn có thể <a href="https://www.mongodb.com/download-center">tải xuống bộ cài tại đây</a>, dành cho nhiều vô số hệ điều hành khác nhau và cài đặt nó trên hệ thống của mình. Bạn cũng có thể sử dụng MongoDB trên đám mây.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Trong bài viết này, ta sẽ sử dụng mLab, một <em>cơ sở dữ liệu được cung cấp dưới dạng dịch vụ</em> trên nền tảng điện toán đám mây và chọn <a href="https://mlab.com/plans/pricing/">sandbox tier</a> nhé. Cái này khá hợp với khâu phát triển, và không phụ thuộc vào việc "cài đặt" hệ điều hành (cơ-sở-dữ-liệu-cung-cấp-dưới-dạng-dịch-vụ là một hướng tiếp cận nếu sử dụng trong dự án thật).</p> -</div> - -<h3 id="Kết_nối_với_MongoDB">Kết nối với MongoDB</h3> - -<p><em>Mongoose</em> yêu cầu một kết nối tới cơ sở dữ liệu MongoDB. Bạn có thể <code>require()</code> và kết nối cục bộ tới cơ sở dữ liệu thông qua <code>mongoose.connect()</code>, như bên dưới.</p> - -<pre class="brush: js">//Nhập mô-đun mongoose -var mongoose = require('mongoose'); - -//Thiết lập một kết nối mongoose mặc định -var mongoDB = 'mongodb://127.0.0.1/my_database'; -mongoose.connect(mongoDB); -//Ép Mongoose sử dụng thư viện promise toàn cục -mongoose.Promise = global.Promise; -//Lấy kết nối mặc định -var db = mongoose.connection; - -//Ràng buộc kết nối với sự kiện lỗi (để lấy ra thông báo khi có lỗi) -db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> - -<p>Bạn có thể lấy ra đối tượng mặc định <code>Connection</code> với <code>mongoose.connection</code>. Ngay khi đã kết nối, sự kiện sẽ nổ ra trên thuộc tính <code>Connection</code>.</p> - -<div class="note"> -<p><strong>Mẹo:</strong> Nếu bạn muốn thêm mới các kết nối khác thì có thể dùng <code>mongoose.createConnection()</code>. Vẫn dùng chung định dạng URI (bao gồm máy chủ, cơ sở dữ liệu, cổng, lựa chọn khác.) như <code>connect()</code> và trả về một đối tượng <code>Connection</code>).</p> -</div> - -<h3 id="Định_nghĩa_và_tạo_ra_các_model">Định nghĩa và tạo ra các model</h3> - -<p>Model được <em>định nghĩa </em>thông qua giao diện <code>Schema</code>. Schema định nghĩa các trường được lưu trong mỗi document đi kèm với điều kiện xác thực và giá trị mặc định cho chúng. Hơn nữa, bạn có thể khởi tạo các thuộc tính tĩnh và phương thức hỗ trợ để làm việc với kiểu dữ liệu của bạn dễ dàng hơn, và cả các đặc tính ảo để có thể dùng như bất cứ trường nào, mà không bị lưu vào trong cơ sở dữ liệu (ta sẽ bàn về vấn đề này sau).</p> - -<p>Schema sau đó được "biên dịch" thành mô hình qua phương thức <code>mongoose.model()</code>. Một khi đã có mô hình thì bạn có thể dùng nó để tìm, thêm, sửa, và xoá các đối tượng cùng kiểu.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Mỗi mô hình có liên kết tới một <em>bộ sưu tập</em> các<em> tài liệu</em> trong cơ sở dữ liệu MongoDB. Documents sẽ chứa các trường/kiểu schema được định nghĩa trong mô hình <code>Schema</code>.</p> -</div> - -<h4 id="Định_nghĩa_schema">Định nghĩa schema</h4> - -<p>Đoạn code bên dưới trình bày cách cách thức tạo ra một Schema đơn giản. Đầu tiên bạn <code>require()</code> mongoose, rồi dùng phương thức khởi tạo của Schema để tạo ra một biến schema, định nghĩa một vài trường trong tham số truyền vào của phương thức khởi tạo.</p> - -<pre class="brush: js">//Require Mongoose -var mongoose = require('mongoose'); - -//Định nghĩa một schema -var Schema = mongoose.Schema; - -var SomeModelSchema = new Schema({ - a_string: String, - a_date: Date -}); -</pre> - -<p>Trong trường hợp trên ta chỉ có 2 trường, một string và một date. Trong phần tiếp theo, ta sẽ thêm một vài trường khác, xác thực, và một số phương thức khác.</p> - -<h4 id="Thêm_mới_một_mô_hình">Thêm mới một mô hình</h4> - -<p>Mô hình được tạo ra từ schema qua phương thức <code>mongoose.model()</code>:</p> - -<pre class="brush: js">// Định nghĩa schema -var Schema = mongoose.Schema; - -var SomeModelSchema = new Schema({ - a_string: String, - a_date: Date -}); - -<strong>// Biên dịch mô hình từ schema -var SomeModel = mongoose.model('SomeModel', SomeModelSchema );</strong></pre> - -<p>Tham số thứ nhất là tên riêng cho collection sắp được tạo ra cho mô hình của bạn (Mongoose sẽ khởi tạo một collection cho model <em>SomeModel</em> ở phía trên), và tham số thứ hai là schema mà bạn muốn dùng để tạo ra mô hình.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Khi đã có các model class, bạn có thể sử dụng chúng để thêm, sửa, hoặc xoá các bản ghi, và để chạy các câu truy vấn lấy tất cả các bản ghi hoặc tạo các tập hợp con cho một số lượng bản ghi nhất định. Ta sẽ tìm hiểu việc này trong phần <a href="#">Sử dụng mô hình</a>, và khi ta tạo khung nhìn.</p> -</div> - -<h4 id="Kiểu_Schema_(các_trường)">Kiểu Schema (các trường)</h4> - -<p>Một schema có thể có số trường thông tin tuỳ ý — mỗi trường đại diện cho một document lưu trong <em>MongoDB</em>. Schema trong ví dụ bên dưới trình bày các kiểu đơn giản của các trường cũng như cách định nghĩa chúng.</p> - -<pre class="brush: js">var schema = new Schema( -{ - name: <strong>String</strong>, - binary: <strong>Buffer</strong>, - living: <strong>Boolean</strong>, - updated: { type: <strong>Date</strong>, default: Date.now }, - age: { type: <strong>Number</strong>, min: 18, max: 65, required: true }, - mixed: <strong>Schema.Types.Mixed</strong>, - _someId: <strong>Schema.Types.ObjectId</strong>, - array: <strong>[]</strong>, - ofString: [<strong>String</strong>], // Bạn có thể tạo mảng cho các trường khác - nested: { stuff: { type: <strong>String</strong>, lowercase: true, trim: true } } -})</pre> - -<p>Hầu hết các <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (đống miêu tả sau từ “type:” hoặc sau tên trường) đều tự định nghĩa chính nó. Ngoại trừ:</p> - -<ul> - <li><code>ObjectId</code>: Đại diện cho các thuộc tính đặc trưng của mô hình trong cơ sở dữ liệu. Chẳng hạn, một cuốn sách có thể dùng thứ này để đại diện cho tác giả của nó. Nó còn sẽ chứa cả ID đặc trưng (<code>_id</code>) cho đối tượng đặc trưng. Ta có thể dùng phương thức <code>populate()</code> để lấy các thông tin liên quan nếu cần thiết.</li> - <li><a href="http://mongoosejs.com/docs/schematypes.html#mixed">Mixed</a>: Một kiểu schema chồng chập.</li> - <li><font face="Consolas, Liberation Mono, Courier, monospace">[]</font>: Mảng. Bạn có thể sử dụng các phương thức cho mảng riêng của JavaScript trên các mô hình này (push, pop, unshift, shift, reduce, vân vân và mây mây.). Ví dụ phía trên có một mảng đối tượng không định kiểu và một mảng đối tượng kiểu <code>String</code>, bạn vẫn có thể định nghĩa một mảng tuỳ ý kiểu đối tượng.</li> -</ul> - -<p>Đoạn code cũng chỉ ra hai cách để khai báo một trường:</p> - -<ul> - <li><em>Tên</em> và <em>kiểu</em> của trường là một cặp khoá-giá trị (ví dụ như với các trường <code>name</code>, <code>binary</code> và <code>living</code>).</li> - <li><em>Tên</em> trường chứa một đối tượng gồm có <code>type</code>, và nhiều <em>lựa chọn</em> khác. Lựa chọn bao gồm những thứ như là: - <ul> - <li>giá trị mặc định.</li> - <li>công cụ xác thực định sẵn (như giá trị max/min) và các hàm tuỳ chỉnh.</li> - <li>Trường ấy có bắt buộc (required) hay không</li> - <li>Trường kiểu <code>String</code> nên tự động ở kiểu chữ nhỏ, chữ to, hoặc tỉa gọn (ví dụ <code>{ type: <strong>String</strong>, lowercase: true, trim: true }</code>)</li> - </ul> - </li> -</ul> - -<p>Để biết thêm chi tiết, mời bạn xem thêm <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> (Tài liệu của Mongoose).</p> - -<h4 id="Xác_thực">Xác thực</h4> - -<p>Mongoose cung cấp một số hàm xác thực định sẵn và tuỳ chỉnh, và các hàm xác thực đồng bộ cũng như bất đồng bộ. Nó cho phép bạn đặc tả cả phạm vi chấp nhận hoặc giá trị và thông báo lỗi khi hàm xác thực gặp phải sự cố trong mọi trường hợp.</p> - -<p>Các hàm xác thực định sẵn bao gồm:</p> - -<ul> - <li>Tất cả các <a href="http://mongoosejs.com/docs/schematypes.html">SchemaTypes</a> đều có hàm xác thực là <a href="http://mongoosejs.com/docs/api.html#schematype_SchemaType-required">required</a>. Hàm này xác minh rằng liệu trường dữ liệu đó có bắt buộc phải được cung cấp nếu muốn lưu lại vào trong document hay không.</li> - <li><a href="http://mongoosejs.com/docs/api.html#schema-number-js">Numbers</a> có hai hàm là <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-min">min</a> và <a href="http://mongoosejs.com/docs/api.html#schema_number_SchemaNumber-max">max</a>.</li> - <li><a href="http://mongoosejs.com/docs/api.html#schema-string-js">Strings</a> có: - <ul> - <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-enum">enum</a>: đặc tả tập các giá trị được cho phép truyền vào trường tương ứng.</li> - <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-match">match</a>: đặc tả một regex để tạo luật cho xâu truyền vào.</li> - <li><a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-maxlength">maxlength</a> và <a href="http://mongoosejs.com/docs/api.html#schema_string_SchemaString-minlength">minlength</a> cho xâu truyền vào.</li> - </ul> - </li> -</ul> - -<p>Ví dụ bên dưới (hơi khác một chút so với tài liệu của Mongoose) chỉ ra cách để thêm các hàm xác minh và thông báo lỗi:</p> - -<pre class="brush: js"><code> - var breakfastSchema = new Schema({ - eggs: { - type: Number, - min: [6, 'Too few eggs'], - max: 12 - required: [true, 'Why no eggs?'] - }, - drink: { - type: String, - enum: ['Coffee', 'Tea', 'Water',] - } - }); -</code></pre> - -<p>Để biết thêm thông tin chi tiết về các hàm xác minh, hãy vào <a href="http://mongoosejs.com/docs/validation.html">Validation</a> (tài liệu của Mongoose) để tìm đọc.</p> - -<h4 id="Thuộc_tính_ảo">Thuộc tính ảo</h4> - -<p>Thuộc tính ảo là các thuộc tính của document mà bạn có thể lấy ra và đặt lại mà không làm ảnh hưởng tới MongoDB. Hàm lấy ra hiệu quả cho việc định dạng lại hoặc kết hợp các trường, trong khi hàm đặt lại lại hữu dụng cho việc phân tách một giá trị riêng lẻ thành nhiều giá trị trong cơ sở dữ liệu. Ví dụ trong tài liệu khởi tạo (và huỷ tạo) một thuộc tính ảo tên đầy đủ từ trường họ và tên, điều đó sẽ dễ dàng và sạch sẽ hơn thay vì tạo ra một trường họ tên mỗi khi có ai đó sử dụng mẫu.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Ta sẽ dùng thuộc tính ảo trong thư viện để định nghĩa một URL đặc trưng cho từng bản ghi của mô hình thông qua một đường dẫn và giá trị của mỗi bản ghi <code>_id</code> của mỗi bản ghi.</p> -</div> - -<p>Để biết thêm chi tiết hãy vào <a href="http://mongoosejs.com/docs/guide.html#virtuals">Virtuals</a> (tài liệu của Mongoose).</p> - -<h4 id="Phương_thức_và_câu_truy_vấn_trợ_giúp">Phương thức và câu truy vấn trợ giúp</h4> - -<p>Một schema có thể còn có <a href="http://mongoosejs.com/docs/guide.html#methods">phương thức biến</a>, <a href="http://mongoosejs.com/docs/guide.html#statics">phương thức tĩnh</a>, và <a href="http://mongoosejs.com/docs/guide.html#query-helpers">hỗ trợ truy vấn</a>. Phương thức biến và phương thức tĩnh gần như tương tự nhau, điểm khác biệt duy nhất là phương thức tĩnh liên kết với một bản ghi xác định và có quyền truy cập tới đối tượng hiện tại. Hỗ trợ truy vấn cho phép bạn mở rộng <a href="http://mongoosejs.com/docs/queries.html">chainable query builder API</a> của mongoose (ví dụ như, cho phép bạn thêm câu truy vấn "byName" sau các phương thức <code>find()</code>, <code>findOne()</code> và <code>findById()</code>).</p> - -<h3 id="Sử_dụng_mô_hình">Sử dụng mô hình</h3> - -<p>Ngay khi đã có một schema, bạn có thể dùng nó để tạo ra các mô hình. Mô hình đại diện cho một bộ sưu tập các tài liệu trong cơ sở dữ liệu mà bạn có thể tìm kiếm, trong khi các phần tử của mô hình đại diện cho từng tài liệu mà bạn có thể lưu trữ và truy xuất.</p> - -<p>Chúng ta chỉ có thể tìm hiểu sơ qua như trên thôi. Nếu muốn chi tiết hơn thì hãy vào xem: <a href="http://mongoosejs.com/docs/models.html">Models</a> (tài liệu của Mongoose).</p> - -<h4 id="Thêm_mới_và_chỉnh_sửa_tài_liệu">Thêm mới và chỉnh sửa tài liệu</h4> - -<p>Để thêm mới một bản ghi, bạn có thể định nghĩa một phần tử của mô hình và sau đó dùng lời gọi <code>save()</code>. Ví dụ bên dưới chỉ ra rằng SomeModel là một đối tượng (chỉ có một trường là "name") mà ta vừa tạo ra từ schema của mình.</p> - -<pre class="brush: js"><code>// Thêm mới một phần tử của mô hình SomeModel -var awesome_instance = new </code>SomeModel<code>({ name: 'awesome' }); - -// Lưu phần tử vừa thêm mới lại, thông qua việc truyền vào một hàm callback -awesome_instance.save(function (err) { - if (err) return handleError(err); - // saved! -}); -</code></pre> - -<p>Việc thêm bản ghi (đi kèm với sửa, xoá, và tìm kiếm) là các công việc bất đồng bộ — bạn phải truyền vào một hàm callback sau khi công việc hoàn tất. API sử dụng quy ước lỗi-trước, thế nên tham số thứ nhất trong hàm callback luôn là một giá trị lỗi (hoặc null). Nếu API trả về kết quả nào đó, nó sẽ được truyền vào qua tham số thứ hai.</p> - -<p>Bạn cũng có thể sử dụng <code>create()</code> để vừa định nghĩa một phần tử của mô hình vừa lưu lại nó luôn. Hàm callback sẽ trả về một lỗi ứng với tham số thứ nhất và phần tử của mô hình vừa khởi tạo qua tham số thứ hai.</p> - -<pre class="brush: js">SomeModel<code>.create({ name: 'also_awesome' }, function (err, awesome_instance) { - if (err) return handleError(err); - // lưu! -});</code></pre> - -<p>Mỗi mô hình đều có một kết nối liên quan (kết nối sẽ mặc định nếu dùng lệnh <code>mongoose.model()</code>). Bạn thêm mới một kết nối và gọi lệnh <code>.model()</code> để tạo thêm tài liệu trên một cơ sở dữ liệu khác.</p> - -<p>Bạn có thể truy cập vào trường của bản ghi mới thông qua cú pháp chấm (.) , và thay đổi giá trị ở trong. Bạn sẽ phải gọi <code>save()</code> hoặc <code>update()</code> để lưu lại giá trị vừa chỉnh sửa vào cơ sở dữ liệu.</p> - -<pre class="brush: js">// Truy cập vào trường dữ liệu của bản ghi qua cú pháp (.) -console.log(<code>awesome_instance.name</code>); //sẽ in ra '<code>also_awesome</code>' - -// Thay đổi bản ghi bằng cách chỉnh sửa trường thông tin, sau đó gọi lệnh save(). -<code>awesome_instance</code>.name="New cool name"; -<code>awesome_instance.save(function (err) { - if (err) return handleError(err); // lưu! - });</code> -</pre> - -<h4 id="Tìm_kiếm_các_bản_ghi">Tìm kiếm các bản ghi</h4> - -<p>Bạn có thể tìm kiếm các bản ghi bằng các phương thức truy vấn, viết các câu truy vấn như đối với một tài liệu JSON. Đoạn code phía dưới trình bày cách tìm kiếm các vận động viên chơi ten-nít trong cơ sở dữ liệu, chỉ trả về các trường như <em>tên</em> và <em>tuổi </em>của vận động viên. GIờ ta sẽ chỉ xác định ra một trường (thể thao) bạn có thể thêm bao nhiêu tiêu chí tuỳ ý, xác định thêm các tiêu chí với regex, hoặc loại bỏ tất cả các điều kiện để trả về tất cả các vận động viên.</p> - -<pre class="brush: js"><code>var Athlete = mongoose.model('Athlete', yourSchema); - -// tìm tất cả các vận động viên chơi tennis, chọn hai trường 'name' và 'age' -Athlete.find({ 'sport': 'Tennis' }, 'name age', function (err, athletes) { - if (err) return handleError(err); - // 'athletes' chứa danh sách các vận động viên phù hợp với tiêu chí đã đề ra. -})</code></pre> - -<p>Nếu bạn ném vào môt hàm callback, như ở trên, câu truy vấn sẽ được thực thi ngay lập tức. Hàm callback sẽ được gọi khi câu truy vấn hoàn tất.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Tất cả các hàm callback trong Mongoose sử dụng mẫu <code>callback(error, result)</code>. Nếu có lỗi xảy ra khi thực hiện câu truy vấn, tham số <code>error</code> sẽ chứa tất cả các lỗi, và <code>result</code> sẽ trở thành null. Nếu câu truy vấn hợp lệ, tham số <code>error</code> sẽ trở thành null, và <code>result</code> sẽ chứa đựng kết quả của câu truy vấn.</p> -</div> - -<p>Nếu bạn không truyền vào một hàm callback nào thì API sẽ trả về một giá trị kiểu <a href="http://mongoosejs.com/docs/api.html#query-js">Query</a>. Bạn có thể sử dụng đối tượng query này để kéo dài câu truy vấn trước khi thực thi nó (thông qua việc truyền vào một hàm callback) sau sử dụng phương thức <code>exec()</code>.</p> - -<pre class="brush: js"><code>// tìm kiếm tất cả các vận động viên -var query = Athlete.find({ 'sport': 'Tennis' }); - -// chọn ra hai trường 'name' và 'age' -query.select('name age'); - -// giới hạn kết quả lại 5 bản ghi -query.limit(5); - -// sắp xếp theo tên -query.sort({ age: -1 }); - -// thực thi câu truy vấn -query.exec(function (err, athletes) { - if (err) return handleError(err); - // athletes chứa một danh sách 5 vận động viên chơi tennis được xếp theo tên -})</code></pre> - -<p>Ở trên ta đưa tất cả điều kiện truy vấn vào trong phương thức <code>find()</code>. Thay vì vậy ta cũng có thể sử dụng hàm <code>where()</code>, và ta có thể xâu chuỗi các lời gọi bằng cú pháp chấm (.) thay vì phải gọi từng câu riêng rẽ. Đoạn code phía dưới làm y chang phần trên, thêm vài điều kiện cho trường tuổi.</p> - -<pre><code>Athlete. - find(). - where('sport').equals('Tennis'). - where('age').gt(17).lt(50). //Điều kiện thêm vào sau hàm where - limit(5). - sort({ age: -1 }). - select('name age'). - exec(callback); // callback ở đây là tên hàm callback của ta.</code></pre> - -<p>Phương thức <a href="http://mongoosejs.com/docs/api.html#query_Query-find">find()</a> lấy ra tất cả các bản ghi thoả mãn điều kiện, nhưng thường thì bạn chỉ muốn lấy ra một thôi. Các phương thức truy vấn phía dưới chỉ lấy ra một bản ghi:</p> - -<ul> - <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findById">findById()</a></code>: Tìm kiếm tài liệu theo <code>id</code> (mỗi tài liệu có một <code>id</code> duy nhất).</li> - <li><code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOne">findOne()</a></code>: Tìm kiếm một tài liệu dựa theo tiêu chí đặt vào.</li> - <li><code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndRemove">findByIdAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#model_Model.findByIdAndUpdate">findByIdAndUpdate()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndRemove">findOneAndRemove()</a></code>, <code><a href="http://mongoosejs.com/docs/api.html#query_Query-findOneAndUpdate">findOneAndUpdate()</a></code>: Tìm kiếm một tài liệu theo <code>id</code> hoặc theo tiêu chí và sửa hoặc xoá nó. Đây là các mẫu có ích khi cần phải tìm kiếm và chỉnh sửa.</li> -</ul> - -<div class="note"> -<p><strong>Lưu ý:</strong> Còn có phương thức <code><a href="http://mongoosejs.com/docs/api.html#model_Model.count">count()</a></code> để đếm số lượng bản ghi phù hợp với điều kiện đề ra. Cái này sẽ có ích nếu bạn chỉ cần tìm ra số lượng thay vì phải kéo về tất cả các bản ghi.</p> -</div> - -<p>Còn có nhiều thứ nữa mà bạn có thể làm với các câu truy vấn. Để biết thêm thông tin mời xem: <a href="http://mongoosejs.com/docs/queries.html">Queries</a> (tài liệu Mongoose).</p> - -<h4 id="Làm_việc_với_tài_liệu_liên_quan_—_sự_cư_ngụ">Làm việc với tài liệu liên quan — sự cư ngụ</h4> - -<p>Bạn có thể thêm mới mối liên quan giữa các tài liệu/phần tử của mô hình qua trường schema <code>ObjectId</code>, hoặc từ một tài liệu đến nhiều qua một mảng <code>ObjectIds</code>. Trường này lưu trữ id của mô hình liên quan. Nếu bạn muốn lấy nội dung của tài liệu liên quan, bạn có thể sử dụng phương thức <code><a href="http://mongoosejs.com/docs/api.html#query_Query-populate">populate()</a></code> trong câu truy vấn để thay thế id với đống dữ liệu tương ứng.</p> - -<p>Chẳng hạn, schema sau đây định nghĩa tác giả và tác phẩm. Mỗi tác giả có thể có nhiều tác phẩm, nên ta sử dụng một mảng đối tượng <code>ObjectId</code>. Mỗi tác phẩm có thể có một tác giả. Thuộc tính "ref" (được in đậm) kể cho ta biết schema nào mà model có thể gắn vào được.</p> - -<pre class="brush: js"><code>var mongoose = require('mongoose') - , Schema = mongoose.Schema - -var authorSchema = Schema({ - name : String, - stories : [{ type: Schema.Types.ObjectId, <strong>ref</strong>: 'Story' }] -}); - -var storySchema = Schema({ - author : { type: Schema.Types.ObjectId, <strong>ref</strong>: 'Author' }, - title : String -}); - -var Story = mongoose.model('Story', storySchema); -var Author = mongoose.model('Author', authorSchema);</code></pre> - -<p>Ta có thể lưu lại đống liên quan đến tài liệu tương ứng bằng cách gán cho nó giá trị <code>_id</code>. Đoạn bên dưới ta tạo ra một tác giả, rồi một cuốn sách và gắn id của tác giả vào trường tác giả của tác phẩm.</p> - -<pre class="brush: js"><code>var bob = new Author({ name: 'Bob Smith' }); - -bob.save(function (err) { - if (err) return handleError(err); - - //Bob giờ đã tồn tại, đến lúc tạo tác phẩm rồi - var story = new Story({ - title: "Bob goes sledding", - author: bob._id // gắn _id của tác giả Bob. ID này được tạo ra mặc định! - }); - - story.save(function (err) { - if (err) return handleError(err); - // Bob giờ đã có tác phẩm của mình - }); -});</code></pre> - -<p>Tài liệu tác phẩm của ta giờ được nối với trường tác giả thông qua ID của trong tài liệu tác giả. Để lấy thông tin của tác giả ta dùng hàm <code>populate()</code>, như bên dưới.</p> - -<pre class="brush: js"><code>Story -.findOne({ title: 'Bob goes sledding' }) -.populate('author') //Thay thế ID của tác giả bằng thông tin của tác giả! -.exec(function (err, story) { - if (err) return handleError(err); - console.log('The author is %s', story.author.name); - // in ra "The author is Bob Smith" -});</code></pre> - -<div class="note"> -<p><strong>Lưu ý:</strong> Ta vừa thêm tác giả vào tác phẩm, nhưng lại không hề thêm tác phẩm vào mảng <code>stories</code> của tác giả. Thế thì làm thế nào để lấy ra tất cả tác phẩm của một tác giả nào đó? Có một cách là thêm tác giả vào mảng tác phẩm, nhưng như thế sẽ thành ra phân vị trí các thành phần trong khi ta cần giữ cho mối liên hệ giữa tác giả với tác phẩm được bảo toàn.</p> - -<p>Cách tốt hơn là lấy <code>_id</code> của <em>tác giả</em>, rồi dùng <code>find()</code> để tìm trong trường tác giả xuyên suốt tác phẩm.</p> - -<pre class="brush: js"><code>Story -.find({ author : bob._id }) -.exec(function (err, stories) { - if (err) return handleError(err); - // trả về tất cả các tác phẩm có id của Bob. -});</code> -</pre> -</div> - -<p>Đến đây là đã đủ hết mọi thứ bạn cần biết trong<em> bài viết này rồi</em>. Để biết thêm thông tin chi tiết, mời bạn tham khảo <a href="http://mongoosejs.com/docs/populate.html">Population</a> (tài liệu của Mongoose).</p> - -<h3 id="Một_schemamô_hình_trên_một_tập_tin">Một schema/mô hình trên một tập tin</h3> - -<p>Dù bạn có thể tạo ra schema và mô hình theo bất cứ kiến trúc nào bạn thích, nhưng chúng tôi vẫn khuyến nghị nên định nghĩa chúng trên mỗi mô đun riêng rẽ (tập tin), rồi xuất mô hình ra ngoài. Làm như thế này này:</p> - -<pre class="brush: js"><code>// Tập tin: ./models/somemodel.js - -//Nhập Mongoose -var mongoose = require('mongoose'); - -//Định nghĩa một schema -var Schema = mongoose.Schema; - -var SomeModelSchema = new Schema({ - a_string : String, - a_date : Date, -}); - -<strong>//Xuất ra lớp mô hình "SomeModel" -module.exports = mongoose.model('SomeModel', SomeModelSchema );</strong></code></pre> - -<p>Sau đó bạn có thể nhập và sử dụng mô hình ngay tắp lự ở bất cứ đâu. Dưới đây là cách bạn lấy ra mọi phần tử của mô hình.</p> - -<pre class="brush: js"><code>//Thê mới mô hình SomeModel thông qua lệnh require -var SomeModel = require('../models/somemodel') - -// Sử dụng đối tượng SomeModel để tìm tất cả bản ghi của SomeModel -SomeModel.find(callback_function);</code></pre> - -<h2 id="Thiết_lập_cơ_sở_dữ_liệu_MongoDB">Thiết lập cơ sở dữ liệu MongoDB</h2> - -<p>Giờ khi đã hiểu những gì Mongoose có thể làm và cách để ta có thể thiết kế một cơ sở dữ liệu, đến lúc thực hành trên trang web <em>LocalLibrary</em> rồi. Bước đầu tiên trong bài thực hành là tạo mới một cơ sở dữ liệu MongoDb để lưu trữ dữ liệu cho thư viện của chúng ta.</p> - -<p>Trong bài viết này ta sẽ sử dụng cơ sở dữ liệu nền điện toán đám mây của <a href="https://mlab.com/welcome/">mLab</a> (chọn kiểu "<a href="https://mlab.com/plans/pricing/">sandbox</a>" để dùng miễn phí). Cơ sở dữ liệu kiểu này không phù hợp dành cho các trang web thật vì nó không có dư thừa dữ liệu, nhưng lại rất hợp dành cho việc phát triển và xây dựng mẫu vật. Và bởi nó dễ dùng cũng như dễ thiết lập, và đừng quên rằng mLab là một trong những bên cung cấp khá nổi tiếng <em>cơ sở dữ liệu cung cấp dưới dạng dịch vụ</em> mà bạn có thể sẽ dùng cho dự án thật (vào thời điểm viết bài này bạn cũng có thể chọn các nhà cung cấp như <a href="https://www.compose.com/">Compose</a>, <a href="https://scalegrid.io/pricing.html">ScaleGrid</a> và <a href="https://www.mongodb.com/cloud/atlas">MongoDB Atlas</a>).</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Nếu bạn muốn thiết lập cơ sở dữ liệu MongoDb cục bộ thì hãy tìm và tải xuống <a href="https://www.mongodb.com/download-center">bản phù hợp với hệ thống của mình</a>. Phần còn lại khá là đơn giản, trừ phần URL của cơ sở dữ liệu mà bạn sẽ phải xác định nếu muốn kết nối tới.</p> -</div> - -<p>Trước hết bạn cần <a href="https://mlab.com/signup/">tạo tài khoản</a> mLab (miễn phí, chỉ cần điền mẫu đăng ký là xong). </p> - -<p>Sau khi đã đăng nhập vào, bạn sẽ được chuyển tới <a href="https://mlab.com/home">trang chủ</a>:</p> - -<ol> - <li>Nhấn <strong>Create New</strong> trong phần <em>MongoDB Deployments</em>.<img alt="" src="https://mdn.mozillademos.org/files/14446/mLabCreateNewDeployment.png" style="height: 415px; width: 1000px;"></li> - <li>Nó sẽ mở ra màn hình <em>Cloud Provider Selection</em>.<br> - <img alt="MLab - screen for new deployment" src="https://mdn.mozillademos.org/files/15661/mLab_new_deployment_form_v2.png" style="height: 931px; width: 1297px;"><br> - - <ul> - <li>Chọn SANDBOX (Free) plan trong phần Plan Type. </li> - <li>Chọn bất cứ nhà cung cấp nào trong phần <em>Cloud Provider</em>. Mỗi nhà cung cấp khác nhau ở các vùng lãnh thổ địa lý khác nhau (ở ngay dưới phần selected plan type).</li> - <li>Bấm nút <strong>Continue</strong>.</li> - </ul> - </li> - <li>Màn hình <em>Select Region</em> mở ra. - <p><img alt="Select new region screen" src="https://mdn.mozillademos.org/files/15662/mLab_new_deployment_select_region_v2.png" style="height: 570px; width: 1293px;"></p> - - <ul> - <li> - <p>Chọn vùng lãnh thổ gần bạn nhất rồi nhấn <strong>Continue</strong>.</p> - </li> - </ul> - </li> - <li> - <p>Màn hình <em>Final Details</em> mở ra.<br> - <img alt="New deployment database name" src="https://mdn.mozillademos.org/files/15663/mLab_new_deployment_final_details.png" style="height: 569px; width: 1293px;"></p> - - <ul> - <li> - <p>Nhập tên cho cơ sở dữ liệu vừa tạo ra như <code>local_library</code> và chọn <strong>Continue</strong>.</p> - </li> - </ul> - </li> - <li> - <p>Màn hình <em>Order Confirmation</em> sẽ mở lên.<br> - <img alt="Order confirmation screen" src="https://mdn.mozillademos.org/files/15664/mLab_new_deployment_order_confirmation.png" style="height: 687px; width: 1290px;"></p> - - <ul> - <li> - <p>Nhấn <strong>Submit Order</strong> để tạo mới cơ sở dữ liệu.</p> - </li> - </ul> - </li> - <li> - <p>Bạn sẽ được điều hướng về trang chủ. Nhấn vào cơ sở dữ liệu vừa thêm mới để xem chi tiết. Như bạn thấy đấy, cơ sở dữ liệu không có bất cứ bộ sưu tập nào (dữ liệu).<br> - <img alt="mLab - Database details screen" src="https://mdn.mozillademos.org/files/15665/mLab_new_deployment_database_details.png" style="height: 700px; width: 1398px;"><br> - <br> - URL mà bạn cần ở ngay đầu trang (trong phần khoanh đỏ). Để dùng được nó bạn phải tạo ra người dùng mới.</p> - </li> - <li>Nhấn vào tab <strong>Users</strong> và bấm nút <strong>Add database user</strong>.</li> - <li>Điền tên đăng nhập và mật khẩu (hai lần), và nhấn nút <strong>Create</strong>. Đừng bao giờ chọn <em>Make read only</em>.<br> - <img alt="" src="https://mdn.mozillademos.org/files/14454/mLab_database_users.png" style="height: 204px; width: 600px;"></li> -</ol> - -<p>Giờ đã có cơ sở dữ liệu rồi, và cả URL (với tên đăng nhập và mật khẩu) đã sẵn sàng để truy xuất. Trông nó sẽ như thế này: <code>mongodb://your_user_namer:your_password@ds119748.mlab.com:19748/local_library</code>.</p> - -<h2 id="Cài_đặt_Mongoose">Cài đặt Mongoose</h2> - -<p>Mở command prompt và chuyển tới thư mục chứa <a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">trang web Local Library</a>. Nhập lệnh dưới để cài đặt Mongoose (và đống dependency của nó) và nó sẽ tự động thêm vào <strong>package.json</strong> của bạn, nếu bạn đã làm như với <a href="#Installing_Mongoose_and_MongoDB">Mongoose Primer</a> ở trên.</p> - -<pre class="brush: bash">npm install mongoose --save -</pre> - -<h2 id="Kết_nối_tới_MongoDB">Kết nối tới MongoDB</h2> - -<p>Mở <strong>/app.js</strong> (trong project của bạn) và sao chép đống phía dưới để khai báo<em> đối tượng ứng dụng Express</em> (sau dòng <code>var app = express();</code>). Thay thế url của cơ sở dữ liệu ('<em>insert_your_database_url_here</em>') bằng URL của mình (như cái vừa tạo ra bằng<a href="#Setting_up_the_MongoDB_database"> mLab</a>).</p> - -<pre class="brush: js">//Thiết lập kết nối tới Mongoose -var mongoose = require('mongoose'); -var mongoDB = '<em>insert_your_database_url_here</em>'; -mongoose.connect(mongoDB); -mongoose.Promise = global.Promise; -var db = mongoose.connection; -db.on('error', console.error.bind(console, 'MongoDB connection error:'));</pre> - -<p>Như đã nói <a href="#Connecting_to_MongoDB">trong phần Mongoose primer phía trên</a>, đoạn code này tạo ra kết nối mặc định tới cơ sở dữ liệu và ràng buộc sự kiện lỗi (để in lỗi ra console). </p> - -<h2 id="Định_nghĩa_Schema_cho_LocalLibrary">Định nghĩa Schema cho LocalLibrary</h2> - -<p>Ta sẽ tạo ra mô đun cho từng mô hình, như <a href="#One_schemamodel_per_file">đã đề cập phía trên</a>. Bắt đầu bằng cách thêm mới thư mục trong thư mục gốc (<strong>/models</strong>) và tạo từng tập tin cho mỗi mô hình:</p> - -<pre>/express-locallibrary-tutorial //the project root - <strong>/models</strong> - <strong>author.js</strong> - <strong>book.js</strong> - <strong>bookinstance.js</strong> - <strong>genre.js</strong> -</pre> - -<h3 id="Mô_hình_tác_giả">Mô hình tác giả</h3> - -<p>Sao chép đoạn code schema <code>Author</code> code bên dưới và dán vào tập tin <strong>./models/author.js</strong>. Scheme định nghĩa rằng một tác giả có kiểu <code>String</code> SchemaTypes cho hai trường họ và tên , bắt buộc và có giới hạn nhiều nhất 100 ký tự, và kiểu <code>Date</code> cho trường ngày sinh và ngày mất.</p> - -<pre class="brush: js">var mongoose = require('mongoose'); - -var Schema = mongoose.Schema; - -var AuthorSchema = new Schema( - { - first_name: {type: String, required: true, max: 100}, - family_name: {type: String, required: true, max: 100}, - date_of_birth: {type: Date}, - date_of_death: {type: Date}, - } -); - -<strong>// Tạo phương thức ảo cho tên đầy đủ -AuthorSchema -.virtual('name') -.get(function () { - return this.family_name + ', ' + this.first_name; -});</strong> - -// Phương thức ảo cho URL của tác giả -AuthorSchema -.virtual('url') -.get(function () { - return '/catalog/author/' + this._id; -}); - -//xuất mô hình -module.exports = mongoose.model('Author', AuthorSchema); - -</pre> - -<p>Ta vừa khai báo <a href="#Virtual_properties">phần ảo</a> cho AuthorSchema với tên là "url" trả về URL tuyệt đối bắt buộc để lấy ra phần tử nhất định của mô hình — ta sẽ dùng thuộc tính này trong mẫu mỗi khi cần lấy ra đường dẫn tới tác giả.</p> - -<div class="note"> -<p><strong>Lưu ý:</strong> Khai báo URL bằng hàm ảo trong schema là ý tưởng tốt bởi vì URL sẽ chỉ cần thay đổi tại một nơi.<br> - Vào lúc này các URL sẽ không thể hoạt động, ta chưa đặt ra các route nào để dẫn lối cho từng phần tử của mô hình. Ta sẽ làm việc này trong các bài viết sau!</p> -</div> - -<p>Sau khi đã xong thì ta xuất mô hình ra thôi.</p> - -<h3 id="Mô_hình_sách">Mô hình sách</h3> - -<p>Sao chép đoạn code schema <code>Book</code> bên dưới và dán nó vào tập tin <strong>./models/book.js</strong>. Làm tương tự đối như với tác giả — ta vừa khai báo một schema có nhiều trường String và một phần ảo để lấy URL của các bản ghi sách, sau đó thì xuất nó ra.</p> - -<pre class="brush: js">var mongoose = require('mongoose'); - -var Schema = mongoose.Schema; - -var BookSchema = new Schema( - { - title: {type: String, required: true}, - <strong> author: {type: Schema.ObjectId, ref: 'Author', required: true},</strong> - summary: {type: String, required: true}, - isbn: {type: String, required: true}, - <strong> genre: [{type: Schema.ObjectId, ref: 'Genre'}]</strong> - } -); - -// Tạo hàm ảo lấy URL của sách -BookSchema -.virtual('url') -.get(function () { - return '/catalog/book/' + this._id; -}); - -//Xuất mô hình -module.exports = mongoose.model('Book', BookSchema); -</pre> - -<p>Sự khác biệt chính là ta vừa tạo ra hai mối liên quan đến sách:</p> - -<ul> - <li>author được trỏ tới mô hình đối tượng <code>Author</code>, và bắt buộc.</li> - <li>genre được trỏ tới một mảng mô hình đối tượng <code>Genre</code>. Ta vẫn chưa định nghĩa đối tượng này!</li> -</ul> - -<h3 id="Mô_hình_BookInstance">Mô hình BookInstance</h3> - -<p>Cuối cùng sao chép đoạn code schema <code>BookInstance</code> bên dưới và dán nó vào tập tin <strong>./models/bookinstance.js</strong>. <code>BookInstance</code> đại diện cho số bản sách mà ai đó mượn, và bao gồm thông itn về thời điểm sách về hoặc hạn trả sách dự kiến, "đánh dấu" hoặc lấy chi tiết phiên bản.</p> - -<pre class="brush: js">var mongoose = require('mongoose'); - -var Schema = mongoose.Schema; - -var BookInstanceSchema = new Schema( - { - book: { type: Schema.ObjectId, ref: 'Book', required: true }, //reference to the associated book - imprint: {type: String, required: true}, - status: {type: String, required: true, <strong>enum: ['Available', 'Maintenance', 'Loaned', 'Reserved']</strong>, <strong>default: 'Maintenance'</strong>}, - due_back: {type: Date, <strong>default: Date.now</strong>} - } -); - -// Lấy ra URL của bookinstance -BookInstanceSchema -.virtual('url') -.get(function () { - return '/catalog/bookinstance/' + this._id; -}); - -//Xuất mô hình -module.exports = mongoose.model('BookInstance', BookInstanceSchema);</pre> - -<p>Các thuộc tính mới được thêm vào trong này nằm trong phần trường dữ liệu:</p> - -<ul> - <li><code>enum</code>: Cho phép ta đặt giá trị chấp nhận được cho xâu truyền vào. Trong trường hợp này ta dùng nó để xác định trạng thái còn sẵn của sách (sử dụng enum sẽ giúp ta tránh khỏi các lỗi chính tả hoặc khai khống giá trị cho trạng thái)</li> - <li><code>default</code>: Ta dùng default để đặt giá trị mặc định cho những bookinstances mới khởi tạo để bảo trì <code>due_back</code> mặc định <code>now</code> (lưu ý cách gọi hàm Date khi thiết lập ngày giờ!)</li> -</ul> - -<p>Những schema còn lại làm tương tự.</p> - -<h3 id="Mô_hình_thể_loại_-_thử_thách!">Mô hình thể loại - thử thách!</h3> - -<p>Mở tập tin <strong>./models/genre.js</strong> của bạn lên và tạo mới một schema để lưu lại thể loại sách (các kiểu sách như là truyện tiểu thuyết, tư liệu lịch sử...).</p> - -<p>Cách định nghĩa cũng giống như các mô hình ở trên:</p> - -<ul> - <li>Mô hình nên có một <code>String</code> SchemaType tên là <code>name</code> để mô tả thể loại.</li> - <li>Tên này phải bắt buộc và có từ 3 đến 100 kí tự.</li> - <li>Tạo một <a href="#Virtual_properties">phương thức ảo</a> cho URL của thể loại, để tên là <code>url</code>.</li> - <li>Xuất mô hình.</li> -</ul> - -<h2 id="Kiểm_thử_—_tạo_ra_vài_bản_ghi">Kiểm thử — tạo ra vài bản ghi</h2> - -<p>Xong xuôi rồi đó. Giờ ta đã có tất cả mô hình!</p> - -<p>Để có thể kiểm thử mô hình (và để tạo ra vài sách mẫu và một số thứ khác ta sẽ dùng trong bài viết sau) ta sẽ chạy một đoạn kịch bản <em>independent</em> để tạo ra các bản ghi cho từng mô hình:</p> - -<ol> - <li>Tải về (hoặc tạo mới) tập tin <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> trong thư mục <em>express-locallibrary-tutorial</em> (đồng cấp với <code>package.json</code>). - - <div class="note"> - <p><strong>Lưu ý:</strong> Bạn không cần hiểu cách thức <a href="https://raw.githubusercontent.com/hamishwillee/express-locallibrary-tutorial/master/populatedb.js">populatedb.js</a> hoạt động; nó chỉ thêm dữ liệu mẫu vào trong cơ sở dữ liệu thôi.</p> - </div> - </li> - <li>Nhập lệnh phía dưới vào trong thư mục chứa project để cài đặt mô-đun <em>async</em> để có thể chạy được đoạn kịch bản (ta sẽ bàn về việc này trong bài tiếp theo, ) - <pre class="brush: bash">npm install async --save</pre> - </li> - <li>Chạy đoạn kịch bản bằng node trong command prompt của bạn, truyền vào URL của cơ sở dữ liệu MongoDB (như cái bạn đã thay thế cho <em>insert_your_database_url_here</em>, trong <code>app.js</code> phía trên): - <pre class="brush: bash">node populatedb <your mongodb url></pre> - </li> - <li>Đoạn code sẽ chạy thành công và in ra những vật được tạo ra trên màn console.</li> -</ol> - -<div class="note"> -<p><strong>Mẹo:</strong> Lên cơ sở dữ liệu của bạn trên <a href="https://mlab.com/home">mLab</a>. Giờ bạn có thể chui vào bộ sưu tập Books, Authors, Genres và BookInstances, và kiểm tra các tài liệu vừa được tạo.</p> -</div> - -<h2 id="Tóm_lại">Tóm lại</h2> - -<p>Trong bài viết này ta học một chút về cơ sở dữ liệu và ORMs trên Node/Express, và cách để định nghĩa schema và mô hình của Mongoose. Sau đó ta đã thực hành thiết kế và triển khai các mô hình <code>Book</code>, <code>BookInstance</code>, <code>Author</code> và <code>Genre</code> cho trang web <em>LocalLibrary</em>.</p> - -<p>Sau cùng ta kiểm thử những gì vừa viết ra bằng cách tạo một đống các phần tử (bằng cách sử dụng một đoạn mã kịch bản). Trong bài tiếp theo ta sẽ học cách tạo các trang để trình bày các thứ.</p> - -<h2 id="Đọc_thêm">Đọc thêm</h2> - -<ul> - <li><a href="https://expressjs.com/en/guide/database-integration.html">Database integration</a> (tài liệu của Express)</li> - <li><a href="http://mongoosejs.com/">Mongoose website</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/guide.html">Mongoose Guide</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/validation.html">Validation</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/schematypes.html">Schema Types</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/models.html">Models</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/queries.html">Queries</a> (tài liệu của Mongoose)</li> - <li><a href="http://mongoosejs.com/docs/populate.html">Population</a> (tài liệu của Mongoose)</li> -</ul> - -<p>{{PreviousMenuNext("Learn/Server-side/Express_Nodejs/skeleton_website", "Learn/Server-side/Express_Nodejs/routes", "Learn/Server-side/Express_Nodejs")}}</p> - -<p> </p> - -<h2 id="In_this_module">In this module</h2> - -<ul> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Introduction">Express/Node introduction</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/development_environment">Setting up a Node (Express) development environment</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Tutorial_local_library_website">Express Tutorial: The Local Library website</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/skeleton_website">Express Tutorial Part 2: Creating a skeleton website</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/mongoose">Express Tutorial Part 3: Using a Database (with Mongoose)</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/routes">Express Tutorial Part 4: Routes and controllers</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/Displaying_data">Express Tutorial Part 5: Displaying library data</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/forms">Express Tutorial Part 6: Working with forms</a></li> - <li><a href="/en-US/docs/Learn/Server-side/Express_Nodejs/deployment">Express Tutorial Part 7: Deploying to production</a></li> -</ul> - -<p> </p> |