35

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 が「未定義」を返し、クエリの結果を返すことです。ある種のブロックメカニズムができると確信していますが、このようなことを行う正しい方法を知りたいです。

4

3 に答える 3

22

ある種のひどいハックなしでこの同期を行う方法はありません。正しい方法は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は、 (ネイティブの MongoDB ドライバーが行うように) promise を返す非同期 API を使用する場合に、同期スタイルでコーディングする方法を提供するようになりました。

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

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メソッド内で呼び出すのではなく、 によって返される promise を直接返すことに注意してくださいfindOne

于 2012-08-19T22:03:08.877 に答える