web-dev-qa-db-ja.com

Node.jsで同期MongoDBクエリを作成する正しい方法は何ですか?

私はMongoDBのNode.JSドライバーを使用していますが、次のような同期クエリを実行したいと思います。

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

問題は、db.openは非同期呼び出し(ブロックしない)であるため、getAThingは "undefined"を返し、クエリの結果を返すようにしたいということです。何らかの種類のブロックメカニズムを使用できると確信していますが、このようなことを行う正しい方法を知りたいと思います。

35
Mike Pateras

この同期をなんらかのひどいハックなしにする方法はありません。正しい方法は、getAThingがパラメーターとしてコールバック関数を受け入れ、thingが使用可能になったらその関数を呼び出すことです。

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

ノード7.6+更新

async/await は、約束を返す非同期API(ネイティブMongoDBドライバーなど)を使用する場合に、同期でコーディングする方法を提供するようになりましたstyleします)。

このアプローチを使用すると、上記のメソッドは次のように記述できます。

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

その後、別のasync関数からlet thing = await getAThing();として呼び出すことができます。

ただし、MongoClientは接続プールを提供するため、このメソッド内で接続プールを開いたり閉じたりしないでください。代わりに、アプリの起動時に_MongoClient.connect_を呼び出してから、メソッドを次のように単純化します。

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

メソッド内でawaitを呼び出さず、代わりにfindOneによって返されるpromiseを直接返すことに注意してください。

19
JohnnyHK

ES 6(ノード8+)

async/await を利用できます

await演算子は、Promiseが解決されるまで非同期関数の実行を一時停止し、値を返します。

これにより、コードは同期的に機能します。

const query = MySchema.findOne({ name: /tester/gi });
const userData = await query.exec();
console.log(userData)



Mongo Sync が利用可能になりました。これはNode.jsで同期MongoDBクエリを作成する正しい方法です。

私はこれを同じものに使用しています。以下のような同期メソッドを書くことができます:

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

注: node-fiber に依存しており、Windows 8ではいくつかの問題があります。

ハッピーコーディング:)

30
Amol M Kulkarni

厳密な同期ではありませんが、繰り返し採用して非常に便利なパターンは、非同期関数で co および promisify yieldを使用することです。 mongoの場合、上記を書き換えることができます。

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 => {

} );

これの意味は:

  1. 任意の非同期ライブラリで「同期」のようなコードを書くことができます
  2. エラーはコールバックからスローされます。つまり、成功チェックは不要です。
  3. 結果を約束として他のコードに渡すことができます
2
Hugheth