Node.js mongodb драйвер async/ждут запросы

У меня есть приложение node.js, использующее собственный драйвер mongodb. В процессе переноса кода моего приложения в async/await с использованием узла v8.9.1 я изо всех сил пытаюсь найти элегантный способ для запросов mongodb. Основная проблема с драйвером mongodb состоит в том, что все запросы используют обратные вызовы, где функции обещаний являются обязательными для асинхронных методов.

Альтернативы:

  • mongoose - обещает, что запросы устарели, и это заставляет использовать модель Schema, что немного накладно для моего приложения.
  • mongoist - якобы отличный, так как он построен с учетом асинхронности/ожидания и полностью обещает, но ошибки с подключением SSL к mongodb и плохим documentations- отвлекли меня от этого решения.

Единственный обходной путь, который мне удалось элегантно реализовать, - это использование пакета npm call -обещания для преобразования API драйвера mongodb в полноценное обещание.

Какие-нибудь свежие идеи для элегантного высокопроизводительного способа?

Ответ 1

Это самый маленький фрагмент кода, который я нашел, который совместим с Mongo3 и async/await. Наслаждайтесь!

module.exports = {
  myFunction: async (query) => {
    let db, client;
    try {
      client = await MongoClient.connect(process.env.MONGODB_CONNECTION_STRING, { useNewUrlParser: true });
      db = client.db(dbName);
      return await db.collection(collectionName).find(query).toArray();
    } finally {
      client.close();
    }
  }
}

Ответ 2

Edit: 'MongoDB' v3.x

в соответствии с будущим mongoDB ES6 вы можете использовать этот способ;

let MongoClient = require('mongodb').MongoClient;
const connectionString = 'mongodb://localhost:27017';

    (async () => {
        let client = await MongoClient.connect(connectionString,
            { useNewUrlParser: true });

        let db = client.db('dbName');
        try {
           const res = await db.collection("collectionName").updateOne({ 
               "someKey": someValue
           }, { $set: someObj }, { upsert: true });

           console.log('res => ${JSON.stringify(res)}');
        }
        finally {
            client.close();
        }
    })()
        .catch(err => console.error(err));

Ответ 3

Благодарю. Отлично работает с ES6:

const middleWare = require('middleWare');
const MONGO = require('mongodb').MongoClient;

router.get('/', middleWare(async (req, res, next) => {
    const db = await MONGO.connect(url);
    const MyCollection = db.collection('MyCollection');
    const result = await MyCollection.find(query).toArray();
    res.send(result);
}))

Ответ 4

Я отправляю это как ответ, потому что я не могу комментировать ответ Идо Лев. Я переведу это, как только достиг 50 репутации.

Не забудьте закрыть соединение db. В противном случае ваше приложение не сможет подключиться к db из-за слишком большого количества открытых подключений (случилось со мной неделю назад).

Ваш запрос может быть успешным или неудачным, поэтому имеет смысл закрыть соединение в finally -block.

const db = await MongoClient.connect(url);
try {
    const stuff = await db.collection("Stuff").find({});
    // Do something with the result of the query
} finally {
    db.close();
}

Обновление: похоже, это также не помогло решить мою проблему. Некоторые люди говорят, что вам даже не нужно закрывать соединение вручную. Кажется, вам лучше использовать ваше соединение через ваше приложение, если это возможно.

Ответ 5

Если u не передает обратный вызов, клиент mongodb возвращает обещание.

Официальный драйвер MongoDB Node.js обеспечивает как основанное на обратном вызове, так и взаимодействие на основе Promised с MongoDB, позволяющее приложениям в полной мере использовать новые функции ES6

Из официальных документов

Ответ 6

mongoose find Query Использование async/wait

Не использовать mongoose.connect в случае async/wait

    var router = require("express").Router()
    var mongoose = require("mongoose")
var await = require("await")
var async = require("async")

    var mongoUrl = "mongodb://localhost:27017/ekaushalnsdc"

    router.get("/async/await/find",async(req, res,  next) => {
      try {
        var db =  await mongoose.createConnection(mongoUrl)
          var colName = db.collection('collectionName')
        var result  = await colName.find({}).toArray()
        res.json(result)
    }catch(ex) {
       res.json(ex.message)
    }
    })

Ответ 7

Если вы хотите работать с курсором без выгрузки в Array, вы не можете использовать await с функциями find() или aggregate(), тогда вы должны использовать код:

UPD by Usas: Для общего случая достаточно ответов toArray().

Но когда задействованы огромные коллекции документов, использование toArray() превысит доступную оперативную память. Таким образом, "высокопроизводительное" решение в таких ситуациях не должно использовать toArray().

В этих случаях вы можете использовать потоки MongoDB, что хорошо работает, но даже проще, чем использование потоков:

const cursor = db.collection('name').aggregate(
    [
        {
            "$match": {code: 10}
        },
        {
          "$count": "count"
        }
    ],
    {
        "allowDiskUse": false
    }
)

for (let doc = await cursor.next(); doc != null; doc = await cursor.next()) {
    console.log('aggregate:', doc.count);
}

Ответ 8

(Основано на ответе "Пакс Бич". За него проголосовали, и я хотел добавить комментарий, объясняющий, почему в некоторых ситуациях ответ Пэта - лучший. У меня недостаточно представителя, чтобы добавлять комментарии.)

Для общего случая достаточно ответов, использующих toArray().

Но когда задействованы огромные коллекции документов, использование toArray() превысит доступную оперативную память. Таким образом, "высокопроизводительное" решение в таких ситуациях не должно использовать toArray().

В этих случаях вы можете использовать потоки MongoDB, что хорошо работает, но даже проще, чем использование потоков:

const cursor = db.collection('someCollection').find({})
for (let doc = await cursor.next(); doc; doc = await cursor.next()) {
    // Process the document.
}

Ответ 9

Поскольку во всех ответах отсутствуют некоторые биты (блоки перехвата, проверка того, что клиент не равен null), я пришел со своим собственным решением. Протестировано с сервером Mongo v4.0.7 и Node JS драйвером 3.2.2.

Обратите внимание, что пример - консольная программа, в которой мы закрываем соединение с сервером в блоке finally. В веб-приложении соединения используются повторно. См. Документы Node Mongo. Кроме того, ошибки регистрируются в библиотеках, таких как Winston или Morgan, а не в консоли.

const MongoClient = require('mongodb').MongoClient;

const url = 'mongodb://localhost:27017';

async function findOne() {

    const client = await MongoClient.connect(url, { useNewUrlParser: true })
        .catch(err => { console.log(err); });

    if (!client) {
        return;
    }

    try {

        const db = client.db("testdb");

        let collection = db.collection('cars');

        let query = { name: 'Volkswagen' }

        let res = await collection.findOne(query);

        console.log(res);

    } catch (err) {

        console.log(err);
    } finally {

        client.close();
    }
}

findOne();