使mongoose.js查询同步运行

我有两个mongoosecollections。 第一个存储地点列表,第二个是访问地点。 我的节点代码通过并试图获取每个地方的访问列表,并构build一个string,我输出为JSON。 第一个查询在第二个开始之前完成 – 是否有办法让它们同步运行?

如果你使用node.js,那么你应该使用https://github.com/caolan/async

当您必须从多个集合中获取数据时,您必须多次链接查询。

这将使你的代码复杂,难以阅读,也没有模块化。 使用asynchronous来使用mongodb和node.js创build模块化

来自我的项目的示例代码:

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 } 

对于mongodb / mongoose查询,没有本地的同步api(并且你不想在实际中使用)。 正如WiredPrarie提到的,你应该把查询链接起来,第二个查询在第一个查询完成并且运行一个callback后开始。 这里是一个例子:

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

如果您使用的是Node 8.x,则可以使用asynchronous/等待: https : //developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

等待操作员暂停执行asynchronous函数,直到Promiseparsing并返回值。 这样你的代码将看起来更同步:

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

查询将陆续执行。

要同步我使用es6-promise。

 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" } ] } ] 

现在mongoose支持承诺,所以你可以.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); }); }); 

这是一个使用MongooseJS进行伪同步请求的替代方法。 这里的想法是创build一个需要执行的查询队列。 然后创build一个recursion调用的函数,直到队列耗尽。 一旦队列耗尽,recursion停止,并为原始请求发回一个响应。 我正在使用Express路由,所以所有这些代码封装在我的路由处理程序。 在这种情况下,一个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;