Bezdepbonusu7Программирование: статьи и ответы

Вопрос

Как правильно сделать синхронный запрос MongoDB в Node.js?

Автор вопроса: Mike PaterasОтветов: 3

Я использую драйвер Node.JS для MongoDB и хочу выполнить синхронный запрос, например:

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", и я хочу, чтобы он возвращал результаты запроса. Я уверен, что мог бы использовать какой-то блокирующий механизм, но я хотел бы знать, как правильно сделать что-то подобное.

javascriptmongodbsynchronous

Ответы

Ответ 1 · рейтинг 22 · JohnnyHK

Невозможно сделать это синхронным без какого-то ужасного взлома. Правильный способ - 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);
                    });
                });
            }
        });
    });
}

Обновление Node 7.6+

async/await теперь предоставляет способ кодирования в синхронном стиле при использовании асинхронных API, которые возвращают промисы (как это делает собственный драйвер MongoDB).

Используя этот подход, описанный выше метод можно записать так:

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.

Ответ 2 · рейтинг 32 · Amol M Kulkarni

ES 6 (узел 8+)

Вы можете использовать async/await.

Оператор await приостанавливает выполнение асинхронной функции до тех пор, пока обещание не будет разрешено и не вернет значение.

Таким образом, ваш код будет работать синхронно:

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

Старое решение - июнь 2013 г. ;)

Теперь доступен Mongo Sync, это правильный способ сделать синхронный запрос MongoDB в Node. js.

Я использую это для того же. Вы можете просто написать метод синхронизации, как показано ниже:

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.

Удачного кодирования :)

Ответ 3 · рейтинг 2 · Hugheth

Хотя это не строго синхронно, шаблон, который я неоднократно использовал и находил очень полезным, заключается в использовании co. и promisify уступают асинхронным функциям. Для монго вы можете переписать приведенное выше:

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. Вы можете передать результат как обещание любому другому фрагменту кода.

Перевод вопроса и ответов сообщества Stack Overflow, лицензия CC BY-SA. Оригинал на Stack Overflow.

Похожие материалы