# Lesson 4 - MongoDB

MongoDB là một hệ quản lý cơ sở dữ liệu (DBMS) phi quan hệ được phát triển bởi MongoDB Inc. Nó là một trong những cơ sở dữ liệu NoSQL phổ biến nhất và thường được sử dụng trong các ứng dụng web hiện đại.&#x20;

Một số ưu điểm nổi trội của MongoDB:

1. **Loại cơ sở dữ liệu NoSQL:** MongoDB lưu trữ dữ liệu dưới dạng tài liệu JSON (BSON, binary JSON) thay vì bảng quan hệ, giúp lưu trữ dữ liệu có cấu trúc linh hoạt hơn.
2. **Horizontal Scaling:** MongoDB hỗ trợ việc mở rộng ngang (horizontal scaling) dễ dàng, cho phép ứng dụng mở rộng mà không cần thay đổi cấu trúc cơ sở dữ liệu.
3. **Tìm kiếm mạnh mẽ:** MongoDB có khả năng tìm kiếm linh hoạt và mạnh mẽ, cho phép bạn truy vấn dữ liệu dựa trên các điều kiện phức tạp và tối ưu hóa hiệu suất.
4. **Dữ liệu không đồng nhất (Unstructured Data):** MongoDB cho phép lưu trữ và truy vấn dữ liệu không đồng nhất, cho phép bạn thay đổi cấu trúc dữ liệu dễ dàng theo thời gian.
5. **Lưu trữ tập tin lớn (GridFS):** MongoDB hỗ trợ lưu trữ và quản lý tập tin lớn như hình ảnh, video, hoặc tệp tin. (tuy nhiên cách này không được recommend nhiều và sẽ có cách lưu trữ tập tin bên thứ 3 - third party).

Sự kết hợp giữa MongoDB và Node.js mang lại nhiều ưu điểm quan trọng cho việc phát triển ứng dụng web và ứng dụng back-end. Dưới đây là một số ưu điểm chính khi sử dụng MongoDB với Node.js:

1. **JavaScript Everywhere:** Cả MongoDB và Node.js đều sử dụng JavaScript, điều này giúp giảm độ phức tạp của việc phát triển và duy trì ứng dụng. Bạn có thể chia sẻ mã nguồn giữa phía máy chủ và phía máy khách, giúp tối ưu hóa quá trình phát triển.
2. **Bất đồng bộ (Asynchronous) và Non-blocking:** Node.js được xây dựng dựa trên mô hình bất đồng bộ, cho phép xử lý hàng loạt yêu cầu mà không cần tạo nhiều luồng hoặc tiến trình. Điều này khớp hoàn hảo với MongoDB, một cơ sở dữ liệu NoSQL hỗ trợ tương tác nhanh chóng và bất đồng bộ.
3. **Hiệu năng cao:** Khi sử dụng MongoDB và Node.js cùng nhau, bạn có khả năng tối ưu hóa hiệu năng ứng dụng của mình. Node.js cho phép xử lý hàng loạt kết nối đồng thời một cách hiệu quả, trong khi MongoDB có khả năng lưu trữ và truy xuất dữ liệu nhanh chóng..
4. **Tích hợp dễ dàng:** Cả Node.js và MongoDB có nhiều thư viện và module phù hợp cho việc kết nối và tương tác với cơ sở dữ liệu. Điều này giúp bạn dễ dàng tích hợp MongoDB vào ứng dụng Node.js của mình.
5. **Khả năng mở rộng:** Cả Node.js và MongoDB hỗ trợ mở rộng dễ dàng. Bạn có thể tăng cường khả năng mở rộng cả ở mức máy chủ (horizontal scaling) và ở mức cơ sở dữ liệu (sharding) khi cần thiết.
6. **Cộng đồng phát triển mạnh mẽ:** Cả Node.js và MongoDB đều có cộng đồng phát triển lớn và sự hỗ trợ mạnh mẽ từ cộng đồng, giúp bạn tìm giải pháp cho các vấn đề mà bạn gặp phải.

## NoSQL

Để hiểu về MongoDB, ta cần phải biết NoSQL là gì.

NoSQL là một thuật ngữ trong lĩnh vực cơ sở dữ liệu (database) để mô tả các hệ thống quản lý dữ liệu không sử dụng cấu trúc dữ liệu quan hệ, khác với cơ sở dữ liệu SQL (Structured Query Language). Điểm chung của các hệ thống NoSQL là chúng không tuân theo mô hình cơ sở dữ liệu quan hệ (RDBMS - Relational Database Management System), trong đó dữ liệu được tổ chức vào các bảng có mối quan hệ với nhau.

Dưới đây là một số đặc điểm chung của cơ sở dữ liệu NoSQL:

1. **Không có Schema Cố định:** Cơ sở dữ liệu NoSQL cho phép lưu trữ dữ liệu không cần phải định nghĩa trước schema cố định. Điều này cho phép lưu trữ dữ liệu có cấu trúc linh hoạt, cho phép thay đổi cấu trúc dữ liệu theo thời gian mà không cần thay đổi cơ sở dữ liệu.
2. **Phân tán và Mở rộng dễ dàng:** Hệ thống NoSQL thường được thiết kế để phân tán và mở rộng dễ dàng, giúp xử lý lượng dữ liệu lớn và tăng cường hiệu năng một cách hiệu quả.
3. **Loại hóa Dữ liệu:** NoSQL có thể lưu trữ nhiều loại dữ liệu khác nhau như tài liệu JSON, dữ liệu cột, dữ liệu key-value, và dữ liệu đồ thị, cho phép phù hợp với nhiều kiểu dữ liệu và ứng dụng.

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/rZ1TY3coIz1nXO3IrOr2/image.png" alt=""><figcaption><p>Mô tả dạng SQL</p></figcaption></figure>

## Cài đặt

Sử dụng MongoDB trong xuyên suốt khoá học ta sẽ có 2 nền tảng:

1. MongoDB Atlas Cloud - nền tảng đám mây lưu trữ database, dễ dàng chia sẻ dữ liệu.
2. MongoDB Manual - sử dụng local (trên máy tính) lưu trữ database, tuy nhiên, hoàn toàn có thể liên kết để sử dụng MongoDB cloud và sử dụng hệ quản trị MongoDB Compass để dễ dàng quản lý (hoặc có thể sử dụng MongoDB Shell để sử dụng các câu lệnh truy vấn - [Link](https://www.mongodb.com/docs/mongodb-shell/)).

Đối với MongoDB Atlas Cloud, cần phải đăng ký và đăng nhập. [Link](https://www.mongodb.com/atlas/database).

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/BjkI21wohm4lvXWrsX7R/image.png" alt=""><figcaption><p>Ví dụ</p></figcaption></figure>

Với MongoDB Manual ta cần phải cài đặt CSDL MongoDB và hệ quản trị MongoDB compass (hoặc các hệ quản trị khác) để sử dụng.

Cài đặt CSDL MongoDB bản Community và MongoDB compass phù hợp với hệ điều hành của máy tại [Link](https://www.mongodb.com/docs/manual/administration/install-community/).

> Trong lúc cài đặt CSDL MongoDB community sẽ có gợi ý cài đặt MongoDB compass và ta sẽ chọn option cài đặt thêm MongoDB compass.

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/W8VzXiMPBTGZFCshreeU/image.png" alt=""><figcaption><p>Ví dụ sau khi cài đặt</p></figcaption></figure>

## Khởi tạo server database

### MongoDB Atlas Cloud

Với MongoDB Atlas Cloud, ta sẽ thấy ngay trên màn hình có nút lựa chọn Create a deployment, ta sẽ chọn và thực hiện theo các bước được yêu cầu trên trang chủ. Sẽ có lựa chọn bản Free với 512Mb và chỉ duy nhất được 1 server dùng free trong một cluster (Một cụm gồm nhiều server) (Trong khoá học ta sẽ lựa chọn bản free này để tiết kiệm chi phí).

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/uEb7AtsIRIHI9iGGmrKi/image.png" alt=""><figcaption><p>Lựa chọn bản Free</p></figcaption></figure>

Đặt tên server và chọn create

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/Efht7TXTyYbfPSctpFs5/image.png" alt=""><figcaption><p>Ví dụ</p></figcaption></figure>

Kết quả sau khi tạo:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/Gt97pf32fxPV9IBoK5hO/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Chọn Browse Collection:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/8fGgfeFSly6EgXyqBdz5/image.png" alt=""><figcaption><p>Browse Collection</p></figcaption></figure>

Chọn Add My Own Data và tạo như bên dưới:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/vX2ZRJObFTBzkpelg92e/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Kết quả:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/PAfVRAzpV804yEnbCJ0P/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Tương tự, hãy tạo thêm Collection users.

### MongoDB Manual (local)

Với local, mặc định port được chạy server mongodb là 27017, bật MongoDB Compass lên, mặc định đường dẫn server mongodb là mongodb://localhost:27017 như hình ảnh và chọn connect.

> Với cách truyền đường dẫn trên, ta hoàn toàn có thể kết nối tới MongoDB Atlas Cloud để sử dụng database trên cloud.

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/zhl0tp805PTW3yBx80aB/image.png" alt=""><figcaption><p>Giao diện bắt đầu MongoDB Compass</p></figcaption></figure>

Kết quả kết nối:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/uq1u3gMvmt5VmSdVtzQi/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Để tạo server database ta sẽ chọn vào Create database, đặt tên database, collection và chọn Create database.

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/3VoIhanYoscib520JdXB/image.png" alt=""><figcaption><p>Tạo server database</p></figcaption></figure>

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/V3AeWZqPn3QYBjDPuy84/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Tương tự, hãy tạo thêm Collection users.

## Cấu trúc database

Phía trên, ta đã cài đặt được database với MongoDB, để làm việc với MongoDB được hiệu quả, ta sẽ cần phải hiểu cấu trúc database trong MongoDB.

MongoDB không sử dụng cấu trúc dạng bảng như relational database, thay vào đó sẽ lưu trữ dữ liệu dưới dạng Document JSON và ta sẽ cần phải hiểu cấu trúc của một database MongoDB sẽ như thế nào qua các thuật ngữ.

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/letOq0v6JluUbElZnmdQ/image.png" alt=""><figcaption><p>Cấu trúc database</p></figcaption></figure>

#### 1. Collections

Collections là nơi chứa nhiều các document json.

Ví dụ: Collection users chứa các bản ghi tài liệu (dữ liệu).

{% hint style="info" %}
Trong SQL là một table.
{% endhint %}

#### 2. Document

Document là một bản ghi của tài liệu (dữ liệu).

{% hint style="info" %}
Trong SQL là một dòng của table.
{% endhint %}

#### 3. Schema

Schema là khái niệm bản lược đồ các thông tin của một document, giúp định nghĩa một document sẽ có những thông tin (Fields) gì.

{% hint style="info" %}
Trong SQL là định nghĩa thông tin của một hàng thông qua thông tin của bảng.
{% endhint %}

#### 4. Fields

Fields là các trường của một document, do dữ liệu trong MongoDB là một bản document JSON.

Trong MongoDB, field '\_id' sẽ giúp định nghĩa tính duy nhất cho một document, giống như Khoá chính trong SQL.

Ví dụ MongoDB database:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/9ITrChq6cscF7mYJzRPC/image.png" alt=""><figcaption><p>Ví dụ database</p></figcaption></figure>

## Kết nối MongoDB với mongoose

Có rất nhiều thư viện hỗ trợ kết nối Server Express với MongoDB và Mongoose là một thư viện, giúp kết nối, xử lý với MongoDB một cách đơn giản để tạo model, dùng cho việc truy vấn với MongoDB.

Thực hiện khởi tạo server với express:

```javascript
import express from 'express';
const app = express();

app.listen(8080, () => {
    console.log('Server is running!');
});
```

Cài đặt mongoose với câu lệnh:

`npm i mongoose`

File package.json:

```json
{
  "name": "server",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "type": "module",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "nodemon index.js"
  },
  "author": "",
  "license": "ISC",
  "dependencies": {
    "express": "^4.18.2",
    "mongoose": "^7.5.3"
  },
  "devDependencies": {
    "nodemon": "^3.0.1"
  }
}
```

Để kết nối với MongoDB, ta cần phải có được chuỗi kết nối tới server MongoDB.

### Connect string

1. Với MongoDB Atlas Cloud làm theo các bước sau:

   <figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/A8dnpWHWt4X7j7qZGlTy/image.png" alt=""><figcaption><p>Chọn connect</p></figcaption></figure>

   <figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/imT5gRkQaI6HSSkxceOl/image.png" alt=""><figcaption><p>Chọn Drivers</p></figcaption></figure>

   <figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/tIElucftd12KlXKfwe87/image.png" alt=""><figcaption><p>Connect string</p></figcaption></figure>

   Connect string sẽ có dạng như ví dụ:

   `mongodb+srv://`<mark style="color:orange;">`<userName>`</mark>`:`<mark style="color:orange;">`<password>`</mark>`@mindx-fullstack.ducckog.mongodb.net/?retryWrites=true&w=majority`
2. Đối với local:

   <figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/lnbzyQsDSyOlqppbqiv3/image.png" alt=""><figcaption><p>Local</p></figcaption></figure>

   Mặc định với local, sẽ có connect string là: mongodb://localhost:27017/{server}

   Nếu muốn dùng tới server database nào chỉ cần replace server, ta sẽ có connect string tới database cần sử dụng. Ví dụ:

   `mongodb://localhost:27017/mindx-fullstack`

{% hint style="info" %}
Nếu như có yêu cầu authentication, bắt buộc cần phải thêm username và password ,... trên đường dẫn.

Ví dụ:

&#x20;mongodb://<mark style="color:orange;">userName</mark>/:<mark style="color:orange;">password</mark>@localhost:27017
{% endhint %}

### Connect mongodb

Sử dụng kết nối tới mongodb với mongoose, ta sẽ theo dõi đoạn code phía dưới đây:

```javascript
import express from 'express';
import mongoose from 'mongoose';

// phương thức connect với tham số connect string
mongoose.connect('mongodb://localhost:27017/mindx-fullstack');
const app = express();

app.listen(8080, () => {
    console.log('Server is running!');
});
```

{% hint style="info" %}
&#x20;Phương thức **`connect`** sẽ có 2 tham số đầu vào theo thứ tự: connect string là bắt buộc và options là không bắt buộc. Đọc thêm tại: [Link](https://mongoosejs.com/docs/connections.html).
{% endhint %}

### Khởi tạo cấu trúc database với mongoose

Trong nội dung phía trên, 2 thông tin chính chúng ta cần phải quan tâm là collections và schema khi sử dụng với mongoose; thư viện sẽ hỗ trợ chúng ta tạo ra model (khuôn dữ liệu, mô hình,...) nhanh chóng, đơn giản (đây cũng chính là một thành phần trong mô hình **MVC**). Theo dõi đoạn code phía dưới và chú thích:

tạo folder `model` và file `users.js`:

```javascript
import mongoose from 'mongoose';
// khởi tạo schema (định nghĩa các field cho các document và kiểu dữ liệu của field đó)
const userSchema = new mongoose.Schema({
    userName: String,
    email: String
});
// định nghĩa model cần truyền với phương thức model và các tham số lần lượt: tên collections, schema của document
const UsersModel = mongoose.model('users', userSchema);
export default UsersModel;
```

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/6FiUWDcOKwknunAbpWke/image.png" alt=""><figcaption><p>users.js</p></figcaption></figure>

Tương tự, làm với model posts và comments:

`posts.js`

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/tXOxLi1BfU0AmdJArUvI/image.png" alt=""><figcaption><p>PostsModel</p></figcaption></figure>

`comments.js`

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/yqsE3WWdjhMy2I7xn5uU/image.png" alt=""><figcaption><p>CommentsModel</p></figcaption></figure>

{% hint style="info" %}
Các tên collection ta nên đặt tên tiếng anh, viết thường và dạng số nhiều, vì nó là tập hợp của nhiều các document.

Có thể tạo 1 Object chứa các key và value là các collection để dễ quản lý và thống nhất giá trị (Recommend).
{% endhint %}

Ví dụ quản lý Collections với Object:

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/rirJKk3AghppMDlPWgeB/image.png" alt=""><figcaption><p>Tạo Object chứa Collections</p></figcaption></figure>

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/nCB1v5UCitHwkGqy6oX8/image.png" alt=""><figcaption><p>Ví dụ</p></figcaption></figure>

Tương tự PostsModel và UsersModel.

{% hint style="info" %}
Trong trường hợp chưa có collection, sẽ được tự động tạo thêm collection tương ứng với tên được truyền vào model.

Trường \_id sẽ được tự động sinh ra mỗi khi một document được thêm vào database
{% endhint %}

## CRUD với mongoose

Ta sẽ thực hành đơn giản với việc cho phép thêm user vào trong database và các vấn đề liên quan.

Tạo api thêm user với resource users, theo dõi đoạn code phía dưới:

```javascript
import express from 'express';
import mongoose from 'mongoose';
import UsersModel from './model/users.js';

mongoose.connect('mongodb://localhost:27017/mindx-fullstack');
const app = express();
app.use(express.json());

app.post('/api/v1/users', async (req, res) => {
    try {
        const { userName, email } = req.body;
        if (!userName) throw new Error('userName is required!');
        if (!email) throw new Error('email is required!');
    
        const createdUser = await UsersModel.create({
            userName,
            email
        });
        res.status(201).send({
            data: createdUser,
            message: 'Register successful!',
            success: true
        });
    } catch (error) {
        res.status(403).send({
            message: error.message,
            data: null,
            success: false
        });
    }
});

app.listen(8080, () => {
    console.log('Server is running!');
});
```

Phương thức **create** giúp thêm mới một document vào trong collection mà model khởi tạo ánh xạ tới, ta cũng sẽ có phương thức giúp thêm nhiều document vào collection một lúc (mảng document) với phương thức **insertMany.**

Tìm hiểu thêm tại [Link](https://mongoosejs.com/docs/api/model.html#Model.create\(\)).

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/chJu95VZ8qnsTS3W5j7e/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Trong trường hợp trên, ta chưa hề kiểm tra đã tồn tại email hay chưa, vì đôi khi ta cũng cần các trường nào đó phải 'unique'. Vậy ta cũng sẽ có một số cách xử lý, ví dụ như tìm kiếm sự tồn tại của thông tin, ví dụ:

```javascript
app.post('/api/v1/users', async (req, res) => {
    try {
        const { userName, email } = req.body;
        if (!userName) throw new Error('userName is required!');
        if (!email) throw new Error('email is required!');
        
        // hàm tìm kiếm 1 bản document với điều kiện được truyền vào
        const existedEmail = await UsersModel.findOne({
            email
        });
        if (existedEmail) throw new Error('Email already exists!');

        const createdUser = await UsersModel.create({
            userName,
            email
        });
        res.status(201).send({
            data: createdUser,
            message: 'Register successful!',
            success: true
        });
    } catch (error) {
        res.status(403).send({
            message: error.message,
            data: null,
            success: false
        });
    }
});
```

Demo

<figure><img src="https://content.gitbook.com/content/bApz6rKK01BWUpp5sM0n/blobs/nd0COF2JdloKSSkEYRuK/image.png" alt=""><figcaption><p>Kết quả</p></figcaption></figure>

Từ đây, ta sẽ có thêm một số phương thức liên quan về tìm kiếm như:

1. **findOne**: tìm kiếm và trả ra *duy nhất một bản ghi*, được tìm thấy đầu tiên với điều kiện được cung cấp, nếu không sẽ trả về undefined, cú pháp:

   `model.findOne(`<mark style="color:orange;">`filter`</mark>`)`

   Với filter là một Object chưa key là trường cần lọc, value là giá trị tương ứng cần lọc

   Ví dụ:

   <pre class="language-javascript"><code class="lang-javascript"><strong>const existedEmail = await UsersModel.findOne({
   </strong>                        email: 'mindx@mail.edu.vn'
                           });
   if (existedEmail) throw new Error('Email already exists!');
   </code></pre>

2. **find**: Tìm kiếm và trả ra một mảng các phần tử là document thoả mãn với điều kiện được cung cấp, tương tự như findOne, nhưng kết quả trả ra *luôn là một mảng* và sẽ là mảng rỗng nếu không có điều kiện nào thoả mãn, khi không truyền hoặc truyền  điều kiện rỗng, sẽ mặc định trả ra toàn bộ collection.

   `model.find(`<mark style="color:orange;">`filter`</mark>`)`

   Ví dụ:

   ```javascript
   const existedEmail = await UsersModel.find({
                           school: 'MindX Technology'
                           });
   ```

3. **findById**: một phương thức tìm kiếm có kết quả trả ra giống với findOne, nhưng tham số truyền vào là giá trị \_id của document cần tìm kiếm. Ví dụ:

   <pre class="language-javascript"><code class="lang-javascript"><strong>const {userId} = req.params;
   </strong><strong>// example: userId = 651aef8a6467af804deed01b
   </strong><strong>const existedEmail = await UsersModel.findById(userId);
   </strong></code></pre>

   Lưu ý:

   mongoose đã hỗ trợ chúng ta convert string sang Object Id để so sánh, chứ không phải tìm kiếm theo string mà ta truyền vào, sẽ xảy ra lỗi nếu như string này không thể convert được vì sai định dạng.

Tham khảo thêm các phương thức liên quan về find tại [Link](https://mongoosejs.com/docs/api/query.html#Query.prototype.findOne\(\)).

Phía trên là giới thiệu sơ qua về thêm, tìm kiếm (CR), vậy còn cập nhật và xoá (UD) ta sẽ tiếp tục làm quen qua một số trường hợp sau.

Viết API để cập nhật thông tin của user, ta sẽ có nhiều cách xử lý khi cập nhật thông tin document, theo dõi đoạn ví dụ cách xử lý với các phương thức sau:

1. **save**

   ```javascript
   app.put('/api/v1/users/:userId', async (req, res) => {
       try {
           // id của user được truyền qua params
           const { userId } = req.params;
           // thông tin cần cập nhật truyền qua body
           const { userName } = req.body;
           // tìm kiếm và kiểm tra tồn tại user
           const currentUser = await UsersModel.findById(userId);
           if (!currentUser) throw new Error('User is not exists!');
           // thực hiện gán lại thông tin
           currentUser.userName = userName;
           // lưu lại trạng thái của document vào database
           await currentUser.save();

           res.status(201).send({
               data: currentUser,
               message: 'Updated info!',
               success: true
           });
       } catch (error) {
           res.status(403).send({
               message: error.message,
               data: null,
               success: false
           });
       }
   });
   ```

   Phương thức **save** sẽ giúp chúng ta lưu lại trạng thái của document vào database nếu như có sự thay đổi, ngoài ra phương thức này cũng có thể dùng để thêm document vào database, đọc thêm tại [Link](https://mongoosejs.com/docs/api/model.html#Model.create\(\)).
2. **findByIdAndUpdate**

   ```javascript
    const { userId } = req.params;
    const { userName } = req.body;
    const currentUser = await UsersModel.findByIdAndUpdate(userId, {
               userName
           });
   ```

   Cách sử dụng hàm này rất đơn giản, tham số thứ nhất là \_id cần tìm, tham số thứ hai là các trường cần cập nhật, kết quả trả về là thông tin của document nếu cập nhật thành công!
3. **findOneAndUpdate, updateOne, updateMany**

   ```javascript
    const {email} = req.query;
    const { userName } = req.body;
    // findOneAndUpdate
    const currentUser = await UsersModel.findOneAndUpdate({email}, {
               userName
           });
   ```

   ```javascript
    // updateOne
     const currentUser = await UsersModel.updateOne({email}, {
               userName
           });
   ```

   Các phương thức này khá giống với findByIdAndUpdate, khác ở chỗ tham số đầu tiên sẽ là filter (điều kiện tìm kiếm), kết quả trả về là thông tin của document nếu cập nhật thành công!

   ```javascript
   // updatMany
     const currentUser = await UsersModel.updateMany({school:'MindX School'}, {
              salary: 1000
           });
   ```

   updateMany là phương thức dùng để cập nhật một lúc nhiều document, tham số truyền giống hai phương thức trên, kết quả trả về là một mảng các document thoả mãn điều kiện

Trên đây là một số phương thức dùng để cập nhật document hoặc nhiều document một lúc mà mongoose hỗ trợ.

Về vấn đề xoá (D), khi đã hiểu về các phương thức cập nhật, thì ta chỉ cần thay chữ update thành delete là ta đã có các phương thức liên quan tới việc xoá document khỏi collection, nhưng ta chỉ cần truyền tham số đầu tiên là filter (điều kiện tìm kiếm).

Từ đó ta sẽ có một số phương thức để xoá document: **findByIdAndDelete**, **findOneAndDelete, deleteOne, deleteMany.**

Tuy nhiên, việc lọc, hay truy vấn theo các hàm được cung cấp sẵn, đôi lúc sẽ không thể bao quát hết được các case thực tế mà chúng ta cần, vậy nên ta sẽ cần phải tìm hiểu thêm nữa về các toán tử [stage](https://www.mongodb.com/docs/manual/reference/operator/aggregation-pipeline/#std-label-aggregation-pipeline-operator-reference) trong mongodb và kết hợp với [aggregate](https://mongoosejs.com/docs/api/aggregate.html#Aggregate\(\)) của mongoose để giúp việc truy vấn dễ dàng, nhanh chóng hơn.

## Tập luyện

Áp dụng các kiến thức được học, thay vì xử lý với json-server, file db.json hãy sử dụng mongodb và mongoose để giải quyết các yêu cầu của Lesson 3, tuy nhiên sẽ có một chút khác biệt như: email cần duy nhất, id sẽ sử dụng \_id mặc định của MongoDB.

## Kết

Trên đây, ta đã được tìm hiểu về MongoDB, cách kết nối, handling database với MongoDB qua thư viện mongoose. Trong bài sau, ta sẽ tìm hiểu cách cấu trúc theo mô hình MVC để dễ dàng quản lý, cũng như phát triển dự án.
