web-dev-qa-db-fra.com

Node.js mynodb driver async/attend des requêtes

J'ai une application node.js utilisant le pilote natif mongodb. Lors de la migration de mon code d'application en mode asynchrone/wait en utilisant le noeud v8.9.1, je peine à trouver un moyen élégant pour les requêtes mongodb. Le problème majeur avec le pilote mongodb est que toutes les requêtes utilisent des callbacks où les fonctions de promesses sont obligatoires pour les méthodes asynchrones. 

Alternatives:

  • mongoose - promet des requêtes obsolètes et il force à utiliser le modèle Schema, ce qui représente un peu de surcharge pour mon application. 
  • mongoist - prétendument génial, car il a été construit avec async/attend en tête et pleinement prometteur, mais des erreurs avec la connexion SSL à mongodb et de mauvaises documentations - m'ont éloignée de cette solution. 

La seule solution de rechange que j'ai réussi à mettre en œuvre de manière élégante consiste à utiliser le package callback-promise npm pour convertir l'API du pilote mongodb en promesse totale. 

Des idées fraîches pour un moyen élégant et performant? 

15
Ido Lev

C'est le plus petit morceau de code que j'ai trouvé qui soit compatible avec Mongo3 et asynchrone/wait .

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();
    }
  }
}
5
Sovattha Sok

Edit: 'mongodb' v3.x

selon mongoDB ES6 future vous pouvez utiliser cette façon;

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));
22
Serhat Ates

Merci. Travailler très bien avec 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);
}))
18
Ido Lev

Je poste ceci comme une réponse parce que je ne peux pas commenter la réponse d'Ido Lev . Je proposerai cela dès que j'aurai atteint 50 points de réputation.

N'oubliez pas de fermer la connexion à la base de données. Sinon, il est possible que votre application ne puisse pas se connecter à la base de données à cause d’un trop grand nombre de connexions ouvertes (m’est arrivé il ya une semaine). 

Votre requête peut réussir ou échouer, il est donc logique de fermer la connexion dans un bloc finally-. 

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();
}

Update: Il semble que cela ne résolve pas non plus mon problème. Certaines personnes disent qu'il n'est même pas nécessaire de fermer la connexion manuellement. Il semble préférable de réutiliser votre connexion avec votre application, si possible.

3
0xC0DEBA5E

Si vous ne passez pas de rappel, le client mongodb renvoie une promesse.

Le pilote officiel MongoDB Node.js fournit une interaction basée sur le rappel ainsi que sur la promesse avec MongoDB, permettant aux applications de tirer pleinement parti des nouvelles fonctionnalités de l'ES6.

Du fonctionnaire docs

3
Surya

mangouste trouver Query Using async/wait 

ne pas utiliser mongoose.connect en cas d'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)
    }
    })
3
muthukumar

Si vous voulez utiliser le curseur sans décharger dans Array, vous ne pouvez pas utiliser les fonctions wait avec find () ou aggreg (), vous devez alors utiliser le code

UPD par Usas: Pour le cas général, les réponses utilisant toArray () sont suffisantes.

Mais lorsque d'énormes collections de documents sont impliquées, l'utilisation de toArray () dépasserait la RAM disponible. Ainsi, une solution "hautes performances" dans ces situations ne doit pas utiliser toArray ().

Pour ces cas, vous pouvez utiliser les flux MongoDB, ce qui fonctionne bien, mais l'utilisation de flux est encore plus simple:

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);
}
2
Pax Beach

(Basé sur la réponse de Pax Beach. Il avait été voté à la baisse et je voulais ajouter un commentaire expliquant pourquoi, dans certaines situations, la réponse de Pat est la meilleure. Je n'ai pas assez de représentant pour ajouter des commentaires.)

Pour le cas général, les réponses utilisant toArray () sont suffisantes.

Mais lorsque énorme collections de documents sont impliquées, utiliser toArray () dépasserait la RAM disponible. Ainsi, une solution "hautes performances" dans ces situations ne doit pas utiliser toArray ().

Pour ces cas, vous pouvez utiliser les flux MongoDB, ce qui fonctionne bien, mais l'utilisation de flux est encore plus simple:

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