it-swarm.com.de

Node.js Mongodb-Treiber async/await-Abfragen

Ich habe eine node.js-Anwendung, die den mongodb-Treiber verwendet. Beim Migrieren meines Anwendungscodes nach async/await mit Knoten v8.9.1 bemühe ich mich, einen eleganten Weg für die mongodb-Abfragen zu finden. Das Hauptproblem des mongodb-Treibers ist, dass alle Abfragen Rückrufe verwenden, bei denen Versprechungsfunktionen für die asynchronen Methoden obligatorisch sind. 

Alternativen:

  • mongoose - verspricht Abfragen, die veraltet sind, und erzwingt die Verwendung des Schemamodells, was für meine App ein wenig Aufwand bedeutet. 
  • mongoist - angeblich großartig, da es asynchron gebaut/erwartet und voll versprochen hat, aber Fehler mit SSL-Verbindung zu mongodb und unzureichenden Dokumentationen haben mich von dieser Lösung abgezogen. 

Die einzige Problemumgehung, die ich auf elegante Weise implementieren konnte, ist die Verwendung des callback-promise npm-Pakets, um die mongodb-Treiber-API vollständig zu konvertieren. 

Irgendwelche frischen Ideen für einen eleganten Hochleistungsweg? 

15
Ido Lev

Dies ist der kleinste Code, den ich gefunden habe und der mit Mongo3 und Async/await kompatibel ist.

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

gemäß mongoDB ES6 future Sie können diesen Weg verwenden;

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

Vielen Dank. Arbeitet gut mit 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

Da bei allen Antworten einige Bits fehlen (catch-Blöcke, überprüfen, ob der Client nicht null ist), habe ich meine eigene Lösung entwickelt. Getestet mit Mongo Server v4.0.7 und Node JS driver 3.2.2.

Beachten Sie, dass es sich bei dem Beispiel um ein Konsolenprogramm handelt, bei dem die Verbindung zum Server im Block finally getrennt wird. In einer Webanwendung werden die Verbindungen wiederverwendet. Siehe Node Mongo-Dokumente . Außerdem werden die Fehler mit Bibliotheken wie Winston oder Morgan und nicht mit der Konsole protokolliert.

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();
9
Jan Bodnar

Ich poste dies als Antwort, da ich die Antwort von Ido Lev nicht kommentieren kann. Ich werde dies umziehen, sobald ich 50 Reputation erreicht habe.

Vergessen Sie nicht, die Datenbankverbindung zu schließen. Andernfalls ist es möglich, dass Ihre Anwendung aufgrund zu vieler offener Verbindungen keine Verbindung zur Datenbank herstellen kann (ist mir vor einer Woche passiert). 

Ihre Abfrage kann erfolgreich sein oder fehlschlagen, daher ist es sinnvoll, die Verbindung in einem finally- Block zu schließen. 

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: Es scheint, dass dies auch mein Problem nicht behoben hat. Einige Leute sagen, dass Sie die Verbindung nicht einmal manuell trennen müssen. Es scheint, dass es am besten ist, wenn möglich, die Verbindung in Ihrer Anwendung erneut zu verwenden.

3
0xC0DEBA5E

Wenn Sie keinen Rückruf übergeben, gibt der mongodb-Client ein Versprechen zurück.

Der offizielle MongoDB Node.js-Treiber bietet sowohl auf Callback basierende als auch auf Promised basierende Interaktion mit MongoDB, sodass Anwendungen die neuen Funktionen von ES6 voll ausnutzen können

Aus den offiziellen docs

3
Surya

mongoose find Query mit async/await 

verwenden Sie nicht mongoose.connect im Falle von async/await 

    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

Wenn Sie mit dem Cursor arbeiten möchten, ohne das Array zu entladen, können Sie waitit nicht mit find () oder aggregate () - Funktionen verwenden. Dann müssen Sie den Code verwenden:

UPD von Usas: Für den allgemeinen Fall sind die Antworten mit toArray () ausreichend.

Bei umfangreichen Dokumentensammlungen würde jedoch die Verwendung von toArray () den verfügbaren Arbeitsspeicher übersteigen. Eine "Hochleistungs" -Lösung in diesen Situationen darf daher nicht für array () verwendet werden.

In diesen Fällen können Sie MongoDB-Streams verwenden, was gut funktioniert, aber noch einfacher als das Verwenden von Streams:

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

(Basierend auf der Antwort von Pax Beach. Es wurde abgelehnt, und ich wollte einen Kommentar hinzufügen, in dem erklärt wird, warum Pats Antwort in manchen Situationen die beste ist.

Für den allgemeinen Fall sind die Antworten mit toArray () ausreichend.

Wenn jedoch riesige Dokumentensammlungen involviert sind, würde die Verwendung von toArray () den verfügbaren Arbeitsspeicher übersteigen. Eine "Hochleistungs" -Lösung in diesen Situationen darf daher nicht für array () verwendet werden.

In diesen Fällen können Sie MongoDB-Streams verwenden, was gut funktioniert, aber noch einfacher als das Verwenden von Streams:

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