Quelle est la bonne façon de faire une requête MongoDB synchrone dans Node.js?

J'utilise le nœud.Pilote JS pour MongoDB, et je voudrais effectuer une requête synchrone, comme ceci:

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, db.open est un appel asychronous (il ne bloque pas), donc le getAThing renvoie "undefined" 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 j'aimerais savoir la bonne façon de faire quelque chose comme ça.

30
demandé sur Mike Pateras 2012-08-20 01:43:07

3 réponses

Il n'y a aucun moyen de faire ce synchrone sans une sorte de hack terrible. La bonne façon est d'avoir getAThing accepter une fonction de rappel en tant que paramètre, puis appeler 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);
                    });
                });
            }
        });
    });
}

Nœud De 7,6+ Mise À Jour

async/await fournit maintenant un moyen de codage dans un style synchrone lors de l'utilisation d'API asynchrones qui renvoient des promesses (comme le fait le pilote MongoDB natif).

En utilisant cette approche, la méthode ci-dessus peut être écrit comme:

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 comme let thing = await getAThing();.

Cependant, il convient de noter que MongoClient fournit un pool de connexions, vous ne devriez donc pas l'ouvrir et le fermer dans cette méthode. Au lieu de cela, appelez MongoClient.connect pendant le démarrage de votre application, puis simplifiez votre méthode en:

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.

17
répondu JohnnyHK 2018-02-13 21:38:58

Maintenant, le Mongo Sync est disponible, c'est la bonne façon de faire une requête MongoDB synchrone dans Node.js.

Je l'utilise 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);

Note: cela dépend du nœud -fibre et certains problèmes sont là avec windows 8.

Codage Heureux :)

30
répondu Amol M Kulkarni 2013-06-07 10:51:53

Bien que ce ne soit pas strictement synchrone, un modèle que j'ai adopté à plusieurs reprises et trouvé très utile est d'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 => {

} );

Cela signifie:

  1. vous pouvez écrire du code de type "synchrone" avec n'importe quelle bibliothèque asynchrone
  2. les erreurs sont lancées à partir des rappels, ce qui signifie que vous n'avez pas besoin de la vérification de succès
  3. vous pouvez transmettre le résultat comme une promesse à tout autre morceau de code
2
répondu Hugheth 2016-05-20 13:56:06