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.
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.
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 :)
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: