web-dev-qa-db-fra.com

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

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.

35
Mike Pateras

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.

19
JohnnyHK

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

30
Amol M Kulkarni

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:

  1. Vous pouvez écrire du code de type "synchrone" avec n'importe quelle bibliothèque asynchrone
  2. Des erreurs sont générées par les rappels, ce qui signifie que vous n'avez pas besoin de la vérification de la réussite
  3. Vous pouvez transmettre le résultat sous forme de promesse à tout autre élément de code
2
Hugheth