Qual é o caminho certo para fazer uma consulta síncrona do MongoDB no Node.js?

Estou usando o driver Node.JS para o MongoDB e gostaria de executar uma consulta síncrona, como:

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; }); }); } }); }); } 

O problema é que db.open é uma chamada asicronosa (não bloqueia), portanto, o getAThing retorna “indefinido” e eu quero que ele retorne os resultados da consulta. Tenho certeza que poderia algum tipo de mecanismo de bloqueio, mas gostaria de saber o caminho certo para fazer algo assim.

Não há como fazer com que isso síncrono seja um tipo de invasão terrível. O caminho certo é ter o getAThing aceitando uma function de retorno de chamada como um parâmetro e, em seguida, chamar essa function quando estiver disponível.

 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); }); }); } }); }); } 

Atualização do Nó 7.6+

async / await agora fornece uma maneira de codificar em um estilo síncrono ao usar APIs assíncronas que retornam promises (como o driver nativo do MongoDB).

Usando essa abordagem, o método acima pode ser escrito como:

 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; } } 

Qual você pode então chamar de outra function async como let thing = await getAThing(); .

No entanto, vale a pena observar que o MongoClient fornece um pool de conexão, portanto, você não deve abri-lo e fechá-lo nesse método. Em vez disso, chame o MongoClient.connect durante a boot do aplicativo e simplifique o método para:

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

Note que não chamamos await dentro do método, em vez de retornar diretamente a promise retornada pelo findOne .

Agora, o Mongo Sync está disponível, esse é o caminho certo para fazer uma consulta síncrona do MongoDB no Node.js.

Eu estou usando isso para o mesmo. Você pode simplesmente escrever o método de synchronization como abaixo:

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

Nota: É dependente da fibra do nó e alguns problemas estão lá no windows 8.

Codificação feliz 🙂

Embora não seja estritamente síncrono, um padrão que eu adotei repetidamente e achei muito útil é usar co e promisify yield em funções assíncronas. Para mongo, você poderia rewrite o acima:

 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 => { } ); 

Isso significa:

  1. Você pode escrever código semelhante a “síncrono” com qualquer biblioteca assíncrona
  2. Erros são lançados a partir dos retornos de chamada, o que significa que você não precisa da verificação de sucesso
  3. Você pode passar o resultado como uma promise para qualquer outro pedaço de código