web-dev-qa-db-de.com

Was ist der richtige Weg, um eine synchrone MongoDB-Abfrage in Node.js durchzuführen?

Ich verwende den Node.JS-Treiber für MongoDB und möchte eine synchrone Abfrage durchführen, z.

function getAThing()
{
    var db = new mongo.Db("mydatabase", server, {});

    db.open(function(err, db)
    {
        db.authenticate("myuser", "mypassword", function(err, success)
        {
            if (success)
            {
                db.collection("Things", function(err, collection)
                {
                    collection.findOne({ name : "bob"}, function(err, thing)
                    {                           
                        return thing;
                    });
                });
            }
        });
    });
}

Das Problem ist, dass db.open ein asynchroner Aufruf ist (er blockiert nicht), daher gibt getAThing "undefined" zurück und ich möchte, dass er die Ergebnisse der Abfrage zurückgibt. Ich bin sicher, ich könnte eine Art Blockierungsmechanismus verwenden, aber ich würde gerne wissen, wie man so etwas richtig macht.

35
Mike Pateras

Es gibt keine Möglichkeit, diese Synchronisierung ohne irgendeine Art von schrecklichem Hack durchzuführen. Der richtige Weg ist, dass getAThing eine Rückruffunktion als Parameter akzeptiert und diese Funktion dann aufruft, sobald thing verfügbar ist.

function getAThing(callback)
{
    var db = new mongo.Db("mydatabase", server, {});

    db.open(function(err, db)
    {
        db.authenticate("myuser", "mypassword", function(err, success)
        {
            if (success)
            {
                db.collection("Things", function(err, collection)
                {
                    collection.findOne({ name : "bob"}, function(err, thing)
                    {       
                        db.close();                    
                        callback(err, thing);
                    });
                });
            }
        });
    });
}

Node 7.6+ Update

async/await bietet jetzt eine Möglichkeit zum Codieren in einem synchronen Stil, wenn asynchrone APIs verwendet werden, die Versprechungen zurückgeben (wie die native MongoDB-Treiber).

Unter Verwendung dieses Ansatzes kann die obige Methode wie folgt geschrieben werden:

async function getAThing() {
    let db = await mongodb.MongoClient.connect('mongodb://server/mydatabase');
    if (await db.authenticate("myuser", "mypassword")) {
        let thing = await db.collection("Things").findOne({ name: "bob" });
        await db.close();
        return thing;
    }
}

Was Sie dann von einer anderen async Funktion als let thing = await getAThing(); aufrufen können.

Beachten Sie jedoch, dass MongoClient einen Verbindungspool bereitstellt, sodass Sie diesen innerhalb dieser Methode nicht öffnen und schließen sollten. Rufen Sie stattdessen MongoClient.connect Während Ihres App-Starts auf und vereinfachen Sie Ihre Methode, um:

async function getAThing() {
    return db.collection("Things").findOne({ name: "bob" });
}

Beachten Sie, dass wir await nicht innerhalb der Methode aufrufen, sondern direkt das Versprechen zurückgeben, das von findOne zurückgegeben wurde.

19
JohnnyHK

ES 6 (Knoten 8+)

Sie können async/await verwenden

Der Operator await unterbricht die Ausführung der asynchronen Funktion, bis das Promise aufgelöst ist, und gibt den Wert zurück.

So funktioniert Ihr Code synchron:

const query = MySchema.findOne({ name: /tester/gi });
const userData = await query.exec();
console.log(userData)



Jetzt ist Mongo Sync verfügbar. Dies ist der richtige Weg, um eine synchrone MongoDB-Abfrage in Node.js durchzuführen.

Ich benutze dies für das gleiche. Sie können die Synchronisationsmethode wie folgt schreiben:

var Server = require("mongo-sync").Server;
var server = new Server('127.0.0.1');
var result = server.db("testdb").getCollection("testCollection").find().toArray();
console.log(result);

Hinweis: Es ist abhängig von Node-Fibre und es gibt einige Probleme mit Windows 8.

Fröhliches Codieren :)

30
Amol M Kulkarni

Es ist zwar nicht streng synchron, aber ein Muster, das ich wiederholt übernommen habe und das sich als sehr nützlich erwiesen hat, ist die Verwendung von co und promisify für asynchrone Funktionen. Für Mongo könnte man folgendes umschreiben:

var query = co( function* () {

    var db = new mongo.Db("mydatabase", server, {});
    db = promisify.object( db );
    db = yield db.open();

    yield db.authenticate("myuser", "mypassword");

    var collection = yield db.collection("Things");
    return yield collection.findOne( { name : "bob"} );

});

query.then( result => {

} ).catch( err => {

} );

Das heisst:

  1. Sie können mit jeder asynchronen Bibliothek "synchronen" Code schreiben
  2. Fehler werden von den Rückrufen ausgelöst, was bedeutet, dass Sie die Erfolgskontrolle nicht benötigen
  3. Sie können das Ergebnis als Versprechen an jeden anderen Code weitergeben
2
Hugheth