J'utilise le pilote Node.JS pour MongoDB, et j'aimerais effectuer une requête synchrone, comme celle-ci:
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;
});
});
}
});
});
}
Le problème est que db.open est un appel asychrone (il ne bloque pas), donc le getAThing renvoie "indéfini" et je veux qu'il renvoie les résultats de la requête. Je suis sûr que je pourrais une sorte de mécanisme de blocage, mais je voudrais savoir la bonne façon de faire quelque chose comme ça.
Il n'y a aucun moyen de faire de ce synchrone sans une sorte de terrible piratage. La bonne façon est que getAThing
accepte une fonction de rappel en tant que paramètre, puis appelle cette fonction une fois que thing
est disponible.
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);
});
});
}
});
});
}
Mise à jour du nœud 7.6+
async
/await
fournit désormais un moyen de coder de manière synchrone style lors de l'utilisation d'API asynchrones qui renvoient des promesses (comme le natif Le pilote MongoDB le fait).
En utilisant cette approche, la méthode ci-dessus peut s'écrire:
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;
}
}
Que vous pouvez ensuite appeler à partir d'une autre fonction async
en tant que let thing = await getAThing();
.
Cependant, il convient de noter que MongoClient
fournit un pool de connexions, vous ne devez donc pas l'ouvrir et le fermer dans cette méthode. Au lieu de cela, appelez MongoClient.connect
Lors du démarrage de votre application, puis simplifiez votre méthode pour:
async function getAThing() {
return db.collection("Things").findOne({ name: "bob" });
}
Notez que nous n'appelons pas await
dans la méthode, mais renvoyons directement la promesse retournée par findOne
.
ES 6 (Noeud 8+)
Vous pouvez utiliser async/wait
L'opérateur await
suspend l'exécution de la fonction asynchrone jusqu'à ce que la promesse soit résolue et renvoie la valeur.
De cette façon, votre code fonctionnera de manière synchrone:
const query = MySchema.findOne({ name: /tester/gi });
const userData = await query.exec();
console.log(userData)
Maintenant, Mongo Sync est disponible, c'est la bonne façon de faire une requête MongoDB synchrone dans Node.js.
J'utilise cela pour la même chose. Vous pouvez simplement écrire la méthode de synchronisation comme ci-dessous:
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);
Remarque: cela dépend de node-fibre et certains problèmes sont là avec Windows 8.
Bon codage :)
Bien qu'il ne soit pas strictement synchrone, un modèle que j'ai adopté à plusieurs reprises et que j'ai trouvé très utile consiste à utiliser co et promisify yield sur les fonctions asynchrones. Pour mongo, vous pouvez réécrire ce qui précède:
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 => {
} );
Ça signifie: