Menu

MongoDB в Node.js: примеры драйвера (find, insert, update)

Работайте с MongoDB из Node.js через официальный драйвер mongodb: подключитесь через MongoClient, затем добавляйте, ищите, обновляйте и удаляйте документы коллекции, всё на async/await.

На этой странице есть исполняемые редакторы: меняйте, запускайте и сразу видите результат.

Чтобы работать с MongoDB из Node.js, установите официальный драйвер (npm install mongodb), подключитесь через new MongoClient(uri), выберите базу через client.db('name') и коллекцию через db.collection('name'). Каждая операция (insertOne, find, updateOne, deleteOne) возвращает промис, поэтому её нужно await. Документы записываются и читаются как обычные объекты JavaScript.

Программа выводит [ 'Dune', 'Neuromancer', 'Hyperion' ]. Базы shop и коллекции books раньше не было: MongoDB создаёт их при первой вставке, а toArray() загружает все документы, на которые указывает курсор find().

Поиск документов с фильтрами и projection

Фильтр это объект, который описывает нужные документы. Обычные значения сравниваются на точное совпадение; операторы вроде $gt, $lt, $in и $regex пишутся во вложенном объекте. projection во втором аргументе выбирает, какие поля вернутся.

В recent две самые новые книги после 1960 года, сначала Hyperion, потом Neuromancer, только с title и year; findOne возвращает первое совпадение (или null), а countDocuments насчитывает 2 книги за 10 и дороже. Замените $gt: 1960 на $gt: 1985, и останется только Hyperion.

Обновление и удаление

updateOne(filter, update) меняет первый подходящий документ. В обновлении используются операторы: $set заменяет поля, $inc прибавляет к числу, $unset удаляет поле, а $push добавляет в массив. updateMany и deleteMany работают со всеми совпадениями.

Обновление нашло и изменило один документ, так что Dune теперь стоит 10, а на складе 2, и после удаления книги без остатка остаётся 1. В обновлении обязательны операторы: передайте { price: 10 } без $set, и драйвер откажет (заменяет документ целиком вызов replaceOne).

ObjectId и индексы

Каждый документ получает _id; если вы его не задали, драйвер создаёт ObjectId. Чтобы найти документ по id, который пришёл строкой (например, из URL), оберните его в new ObjectId(id). Индекс делает поиск по полю быстрым, а уникальный индекс заставляет MongoDB отклонять дубликаты.

ObjectId в виде строки это 24 шестнадцатеричных символа, а поиск по обычной строке ничего не находит, поэтому та строка выводит null. Вторая вставка нарушает уникальный индекс и падает с кодом 11000, так и определяют ситуацию "email уже занят".

MongoDB в API на Express

Подключитесь один раз при запуске сервера и используйте коллекцию везде; не открывайте новое подключение на каждый запрос. Драйвер держит пул соединений и переиспользует их.

GET /books возвращает обе книги, у каждой есть _id. Скопируйте один id в GET /books/<id>, чтобы получить одну книгу, или отправьте POST /books с JSON телом вроде {"title": "Foundation", "year": 1951} и снова запросите список.

В настоящем приложении строка подключения читается из process.env.MONGODB_URI, а не пишется в коде.

Если нужны схемы и валидация поверх драйвера, их даёт Mongoose (npm install mongoose):

const Book = mongoose.model('Book', new mongoose.Schema({ title: String, year: Number }));
await Book.create({ title: 'Dune', year: 1965 });

Частые ошибки

Забыли toArray(). find() возвращает курсор, а не документы. В логе будет объект курсора; вызовите toArray() или пройдите по нему через for await.

Подключение на каждый запрос. Каждый new MongoClient открывает свой пул. Создайте один клиент при запуске и используйте его везде.

Клиент не закрыт в скрипте. Открытый клиент не даёт процессу завершиться, когда ваш код уже отработал. Вызывайте await client.close() в конце скриптов; сервер держит его открытым всё время работы.

Часто задаваемые вопросы

Что выбрать: драйвер mongodb или Mongoose?

Драйвер это официальный и более тонкий слой: вы работаете с обычными объектами и собственным языком запросов MongoDB. Mongoose добавляет поверх него схемы, валидацию и модели, это удобно, когда нужно проверять каждый документ. Оба работают с одной и той же базой, а Mongoose внутри использует драйвер.

Нужно ли сначала создавать базу данных или коллекцию?

Нет. MongoDB создаёт и то, и другое при первой вставке документа. client.db('shop') и db.collection('books') только возвращают ссылки на них.

Где хранить строку подключения?

В переменной окружения, например MONGODB_URI, и читать её через process.env.MONGODB_URI. В строке облачной базы есть пароль, поэтому её нельзя коммитить в репозиторий.

Почему find ничего не находит, когда я ищу по id?

_id хранится как ObjectId, а не как строка, поэтому { _id: '65f1...' } ничего не находит. Сначала преобразуйте его: { _id: new ObjectId(id) }.

Иллюстрация языков программирования Coddy

Учитесь программировать с Coddy

Начать