Перейти до основного вмісту

Драйвер MongoDB

Драйвер MongoDB

Драйвер MongoDB Node.js дозволяє взаємодіяти з базами даних MongoDB з програм Node.js. Драйвер знадобиться нам для підключення до бази даних та виконання запитів. Якщо у вас не встановлено драйвер MongoDB Node.js, ви можете встановити його в проект за допомогою наступної команди.

npm install mongodb

Модуль MongoDB експортує MongoClient, він використовується для підключення до бази даних MongoDB, виконання операцій та закриття з'єднання з цим кластером. Також ми експортуємо ObjectId він знадобиться нам, щоб перетворити рядок до об'єкту _id MongoDB

const { MongoClient, ObjectId } = require('mongodb');

Перше, що нам потрібно зробити це помістити константу URI підключення у змінну оточення DB_HOST. URI підключення - це рядок підключення, Ви скопіювали з Atlas у попередньому розділі. Помістимо її у файл .env

DB_HOST=mongodb+srv://<username>:<password>@<your-cluster-url>/test?retryWrites=true&w=majority

У самій програмі отримаємо доступ до URI

require('dotenv').config();
const uriDb = process.env.DB_HOST;

Тепер, коли ми маємо URI, ми можемо створити екземпляр MongoClient.

const client = await new MongoClient(uriDb, {
useUnifiedTopology: true,
}).connect();

Використати екземпляр MongoClient для підключення до нашого кластера можна після виконання connect(). Функція поверне нам обіцянку, і ми ставимо await, щоб дочекатися екземпляр підключення. Після цього ми готові взаємодіяти з нашою базою даних.

Виклики функцій, що взаємодіють із базою даних, ми помістимо в оператори try/catch, щоб обробляти будь-які несподівані помилки.

try {
// робота з базою даних
} catch (e) {
console.error(e);
}

Насамкінець ми закриваємо підключення до нашої бази, тому закінчуємо try/catch оператором finally.

finally {
await client.close();
}

REST API

Перепишемо на програму з розділу REST API з використанням бази даних MongoDB. Повний код програми:

Модифікації зазнав файл роутингу api/index.js. Розглянемо докладніше зміни та почнемо з обробника роутингу /tasks

router.get('/tasks', async (req, res, next) => {
const client = await new MongoClient(uriDb, {
useUnifiedTopology: true,
}).connect();
try {
const results = await client.db().collection('todos').find().toArray();
res.json({
status: 'success',
code: 200,
data: {
tasks: results,
},
});
} catch (e) {
console.error(e);
next(e);
} finally {
await client.close();
}
});

Ми створюємо екземпляр підключення у базі даних MongoDB. Всю логіку взаємодії ми поміщаємо в оператор try/catch. Знаходимо всі можливі завдання

const results = await client.db().collection('todos').find().toArray();

Тут необхідно звернути увагу, що оператор find повертає нам курсор, та необхідно перетворити його на масив методом toArray . Після ми відправляємо, як і раніше результат у вигляді JSON.

У принципі робота інших обробників загалом схожа і вони мають загальну схему з деякими відмінностями.

При отриманні завдання по id , ми перетворюємо рядок id на об'єкт ObjectId

const objectId = new ObjectId(id);

Після виконуємо деструктуризації єдиного об'єкта завдання

const [result] = await client
.db()
.collection('todos')
.find({ _id: objectId })
.toArray();

І у змінній result лежатиме шуканий об'єкт приблизно такого виду

{
"_id": "5f8644b9cf20df3314f5b7b7",
"title": "My work",
"text": "The best",
"isDone": false
}

Створення нового завдання ми виконуємо наступною командою. Роут очікує об'єкт виду

{
"title": "My work",
"text": "The best"
}

А збереження у базі відбувається через функцію insertOne

const result = await client
.db()
.collection('todos')
.insertOne({ title, text, isDone: false });

Ми вставляємо новий документ у базу і результатом буде об'єкт, що містить:

{
"acknowledged": true,
"insertedId": "61264cb97361c8156dbf793c"
}

Властивість insertedId містить ObjectId із вставленим документом. Відправляємо JSON з отриманим результатом.

res.status(201).json({
status: 'success',
code: 201,
data: { task: result },
});

Оновлення PUT та PATCH майже ідентичні

const { value: result } = await client
.db()
.collection('todos')
.findOneAndUpdate(
{ _id: objectId },
{ $set: { title, text } },
{ returnDocument: 'after' },
);

Результат операції об'єкт з властивістю value , куди драйвер помістить оновлений документ. Першим параметром для функції findOneAndUpdate ми вказуємо критерій пошуку { _id: objectId }. Другий параметр – це об'єкт оновлення { $set: { title, text } }, де ми використовуємо модифікатор $set, щоб відбулося оновлення лише вказаних полів, а не повна заміна документа на ці поля. Третій параметр { returnDocument: 'after' } говорить про те, що ми хочемо отримати не вихідний документ, а вже оновлений.

Видалення виконуємо за допомогою функції findOneAndDelete:

const { value: result } = await client
.db()
.collection('todos')
.findOneAndDelete({ _id: objectId });

Тут ми поступили трохи інакше. Попереднього разу ми повертали статус 204, у цей 200 и удаленный документ.

Зауваження

Слід зазначити, що це спрощений навчальний приклад. Він показує підключення до бази MongoDB та виконання найпростіших запитів. Наприклад, всю логіку роботи ми помістили в роути, але "правильно" було б роботу з базою винести в окремий, сервіс, а логіку роботи обробників перенести на контролери. Також ми не обробляємо помилки відсутності шуканих документів у базі та не повертаємо при цьому помилку 404 (Not found). Ці речі були спеціально опущені, щоб показати саме роботу з драйвером MongoDB, але надалі під час розгляду ODM Mongoose ми побудуємо нашу програму більш "правильно".

API доступно по URL: https://nodebook-api-mongodb.glitch.me/api/tasks/.

І ви знову можете за допомогою Postman виконати усі CRUD операції