使mongoose.js查询同步运行

时间:2022-10-05 02:35:00

I have two mongoose collections. The first stores a list of places, the second is visits to the places. My node code goes through and attempts to get the list of visits to each place and build a string that I output as JSON. The first query completes before the second ever starts - is there a way to make them run synchronously?

我有两个猫鼬收藏品。第一个存储地点列表,第二个是访问地点。我的节点代码经过并试图获取每个地方的访问列表并构建一个我输出为JSON的字符串。第一个查询在第二个查询开始之前完成 - 有没有办法让它们同步运行?

6 个解决方案

#1


15  

If you are using node.js then u should use https://github.com/caolan/async

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

when you have to fetch data from multiple collections you have to chain your queries multiple times.

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

It will make your code complex and difficult to read and no modularity. Use async to create modularity using mongodb and node.js

它会使您的代码变得复杂且难以阅读且无模块化。使用async来使用mongodb和node.js创建模块化

Example Code from my project :

我项目中的示例代码:

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


11  

There is no native synchronous api for mongodb/mongoose queries (and your wouldn't want one in practicality). As WiredPrarie mentions, you should chain the queries, with the second one starting after the first completes and running a callback. Here is an example:

mongodb / mongoose查询没有原生的同步api(你不会想要实用的)。正如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


7  

If you're using Node 8.x you can utilize async/await: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

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

await operator pauses execution of async function until the Promise is resolved and returns the value. This way your code will look more synchronous:

await运算符暂停执行异步函数,直到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();

Queries will be executed in succession.

查询将连续执行。

#4


3  

These days mongoose supports promises, so you can .then() your queries. For example:

这些天mongoose支持promises,所以你可以.then()你的查询。例如:

app.get('/notifications', 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);
  });
});

Alternatively, now that Javascript has async-await, you can use that, which will save a few lines, and flatten the code a bit:

或者,现在Javascript具有async-await,您可以使用它,这将节省几行,并稍微展平代码:

app.get('/notifications', async (req, res, next) => {
  try {
    const user = await Users.findOne({
      username: req.body.username,
      password: req.body.password,
    });
    if (!user) {
      res.json({success: false, message: "Username or password incorrect."});
      return;
    }

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

#5


2  

To synchronize I used es6-promise.

为了同步,我使用了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);
            });
        });
    }
};

and I got JSON like following.

我得到了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"
            }
        ]
    }
]

#6


0  

Here is an alternate method for making pseudo synchronous requests using MongooseJS. The idea here is to create a queue of queries that need to be executed. Then create a function that is called recursively until the queue is exhausted. Once the queue is exhausted, the recursion stops and a response sent back for the original request. I am using Express Routes, so all of this code is encapsulated in my route handler. In this case an HTTP POST.

这是使用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;

#1


15  

If you are using node.js then u should use https://github.com/caolan/async

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

when you have to fetch data from multiple collections you have to chain your queries multiple times.

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

It will make your code complex and difficult to read and no modularity. Use async to create modularity using mongodb and node.js

它会使您的代码变得复杂且难以阅读且无模块化。使用async来使用mongodb和node.js创建模块化

Example Code from my project :

我项目中的示例代码:

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


11  

There is no native synchronous api for mongodb/mongoose queries (and your wouldn't want one in practicality). As WiredPrarie mentions, you should chain the queries, with the second one starting after the first completes and running a callback. Here is an example:

mongodb / mongoose查询没有原生的同步api(你不会想要实用的)。正如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


7  

If you're using Node 8.x you can utilize async/await: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/await

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

await operator pauses execution of async function until the Promise is resolved and returns the value. This way your code will look more synchronous:

await运算符暂停执行异步函数,直到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();

Queries will be executed in succession.

查询将连续执行。

#4


3  

These days mongoose supports promises, so you can .then() your queries. For example:

这些天mongoose支持promises,所以你可以.then()你的查询。例如:

app.get('/notifications', 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);
  });
});

Alternatively, now that Javascript has async-await, you can use that, which will save a few lines, and flatten the code a bit:

或者,现在Javascript具有async-await,您可以使用它,这将节省几行,并稍微展平代码:

app.get('/notifications', async (req, res, next) => {
  try {
    const user = await Users.findOne({
      username: req.body.username,
      password: req.body.password,
    });
    if (!user) {
      res.json({success: false, message: "Username or password incorrect."});
      return;
    }

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

#5


2  

To synchronize I used es6-promise.

为了同步,我使用了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);
            });
        });
    }
};

and I got JSON like following.

我得到了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"
            }
        ]
    }
]

#6


0  

Here is an alternate method for making pseudo synchronous requests using MongooseJS. The idea here is to create a queue of queries that need to be executed. Then create a function that is called recursively until the queue is exhausted. Once the queue is exhausted, the recursion stops and a response sent back for the original request. I am using Express Routes, so all of this code is encapsulated in my route handler. In this case an HTTP POST.

这是使用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;