Выполнение запросов mongoose.js синхронно - программирование
Подтвердить что ты не робот

Выполнение запросов mongoose.js синхронно

У меня есть две коллекции мангустов. Первый хранит список мест, второй - посещение мест. Пройдет мой node код и попытается получить список посещений в каждом месте и построить строку, которую я выводил как JSON. Первый запрос завершается до начала второго запуска - есть ли способ заставить их работать синхронно?

4b9b3361

Ответ 1

Если вы используете node.js, тогда вы должны использовать https://github.com/caolan/async

когда вам нужно извлекать данные из нескольких коллекций, вам нужно несколько раз связывать свои запросы.

Это сделает ваш код сложным и трудным для чтения и без модульности. Использовать async для создания модульность с использованием mongodb и node.js

Пример кода из моего проекта:

var async = require('async');

var createGlobalGroup = function(socket, data) {
    async.waterfall(
    [
    /**
     * this function is required to pass data recieved from client
     * @param  {Function} callback To pass data recieved from client
     */

    function(callback) {
        callback(null, socket, data);
    },
    /**
     * Step 1: Verify User
     */
    verifyUser,
    /**
     * Step 2: Check User Access Rights And Roles
     */
    checkUserAccessRightsAndRoles,
    /**
     * Step 3: Create Project
     */
    createNewGlobalGroup], function(err, result) {
        /**
         * function to be called when all functions in async array has been called
         */
        console.log('project created ....')
    });
}
verifyUser = function(socket, data, callback) {
//do your query
    /**
     * call next function in series
     * provide sufficient input to next function
     */
    callback(null, socket, data, {
        "isValidUser": true,
    });
}

checkUserAccessRightsAndRoles = function(socket, data, asyncObj, callback) {
    //do your query
    if(condition) {
        callback(null, socket, data, {
            roles: result,
            "isValidUser": asyncObj.isValidUser,
            "userId": asyncObj.userId,
        });
    } else {
    //no call back
    }
}

var createNewGlobalGroup = function(socket, data, asyncObj, callback) {
//wanna stop then no callback
}

Ответ 2

Существует не родной синхронный api для запросов mongodb/mongoose (и вы не захотите этого в практичности). Как упоминает WiredPrarie, вам нужно связать запросы, а второй - после первого завершения и выполнения обратного вызова. Вот пример:

function findVisits(placesQuery,callback){
    Places.find(placesQuery).exec(function(err,places){
        if (err || !places.length){
            console.log('there was a problem');
            callback(err, null);
        }else{
            var visitQuery = ... //however you want to filter places
            Visits.find(visitQuery).exec(function(err2,visits){
                if (err2 || !visits.length){
                    console.log('there was a problem');
                    callback(err2,null);
                }else{
                    callback(null, visits)
                }
            });
        }
    });
}

Ответ 3

Если вы используете Node 8.x, вы можете использовать async/wait: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

Оператор

wait приостанавливает выполнение async-функции до тех пор, пока Promise не будет разрешен и не вернет значение. Таким образом, ваш код будет выглядеть более синхронно:

const query1 = MyModel.find({ name: /john/i }, null, { skip: 10 });
const result1 = await query1.exec();

const query2 = MyModel.find({ name: /john/i }, null, { skip: 100 });
const result2 = await query2.exec();

Запросы будут выполняться последовательно.

Ответ 4

Для синхронизации я использовал es6-обещание.

var Promise = require('es6-promise').Promise
  , mongoose = require('mongoose')
  , Schema = mongoose.Schema;

// define schemas and models.
var placeSchema = new Schema({
        name: { type: String },
        memo: { type: String }
    })
  , Places = mongoose.model('place', placeSchema)
  , visitSchema = new Schema({
        placeName: { type: String }, // foreign key for place.
        visitor: { type: String },
        comment: { type: String }
    })
  , Visits = mongoose.model('visit', visitSchema);

// query for visits by visitor and place.
function findVisitsWithPlace(visitor, place) {
    return new Promise(function (resolve, reject) {
        Visits.find({
            visitor: visitor,
            placeName: place.name
        }, function (error, visits) {
            if (error) {
                reject(error);
                return;
            }

            // build a result object you want.
            // ()
            resolve({
                place: place,
                visits: visits
            });
        });
    });
}

// functions for node route.
module.exports = {
    // - access to "GET /placevisits/?visitor=Visitor-1".
    get: function (request, response) {
        var visitor = request.query.visitor;

        // - to get the places...
        Places.find({}, function (error, places) {
            Promise.all(places.map(function (place) {
                // - run the child queries with parent object...
                return findVisitsWithPlace(visitor, place);
            })).then(function (placeAndVisits) {
                // - and get result.
                // placeAndVisits have still contain visits empty.
                // exclude them.
                var result = [];
                placeAndVisits.forEach(function (placeandvisit) {
                    if (placeandvisit.visits.length != 0) {
                        result.push(placeandvisit);
                    }
                });
                response.json(result);
            });
        });
    }
};

и я получил JSON, как показано ниже.

[
    {
        "place": {
            "_id": "564e58a1dbed862155771d46",
            "name": "Place-A",
            "memo": "A memo for Place A."
        },
        "visits": [
            {
                "_id": "564e58cedbed862155771d49",
                "placeName": "Place-A",
                "visitor": "Visitor-1",
                "comment": "A comment for Place A by Visitor-1"
            },
            {
                "_id": "564e58dcdbed862155771d4a",
                "placeName": "Place-A",
                "visitor": "Visitor-1",
                "comment": "2nd visit. Again comment for Place A by Visitor-1"
            }
        ]
    },
    {
        "place": {
            "_id": "564e58afdbed862155771d47",
            "name": "Place-B",
            "memo": "A memo for Place B."
        },
        "visits": [
            {
                "_id": "564e58ebdbed862155771d4c",
                "placeName": "Place-B",
                "visitor": "Visitor-1",
                "comment": "A comment for Place B by Visitor-1"
            }
        ]
    }
]

Ответ 5

В наши дни mongoose поддерживает promises, поэтому вы можете .then() ваши запросы. Например:

app.get(function (req, res, next) {
  Users.findOne({
    username: req.body.username,
    password: req.body.password,
  }).then(user => {
    if (!user) {
      res.json({success: false, message: "Username or password incorrect."});
      return;
    }

    return Notifications.find({
      user: user._id
    }).then(notifications => {
      res.json({success: true, notifications});
    });
  ).catch(error => {
    //console.error(error);
    //res.json({success: false, error: error.message});
    next(error);
  });
});

Ответ 6

Вот альтернативный метод для создания псевдосинхронных запросов с использованием MongooseJS. Идея здесь заключается в создании очереди запросов, которые необходимо выполнить. Затем создайте функцию, которая называется рекурсивно, до тех пор, пока очередь не будет исчерпана. После того, как очередь будет исчерпана, рекурсия прекращается и ответ отправляется назад для первоначального запроса. Я использую Express Routes, поэтому весь этот код инкапсулирован в моем обработчике маршрутов. В этом случае HTTP POST.

var express = require('express');
var router = express.Router();

//POST /auth/create
router.post('/create', function(req, res) {
    var queue = [
        {"schema": require('..\\models\\people.js'), "query": {username: req.body.username}},
        {"schema": require('..\\models\\members.js'), "query": {username: req.body.username}}
    ],
    retData = []; 

    var curTask = 0.


    function recurse()
    {   
        if(curTask < queue.length){
                var task = queue[curTask];
                task.schema.findOne(task.query, function(err, data){
                retData.push(err || data);
                curTask++;
                recurse();
            })
        }else{
            res.json(retData);
        }

    }

    recurse();

});



module.exports = router;