admin管理员组文章数量:1287913
I'm trying to initialize two input with autoplete with this library. When I load my page, I will trigger an Ajax to initialize two input text.
But I don't know how I can detect when all my mongoose find are pleted.
Here is my server side code :
app.post('/init/autoplete', function(req, res){
var autoplete = {
panies: [],
offices: []
};
// Find all panies
Company.find({}, function(err, panies) {
if (err) throw err;
panies.forEach(function(pany) {
autopletepanies.push({value: pany.name})
});
console.log('One');
});
// Find all offices
Office.find({}, function(err, offices) {
if (err) throw err;
offices.forEach(function(office) {
autoplete.offices.push({value: office.name})
});
console.log('Two');
});
console.log('Three');
// res.json(autoplete);
});
I know than the find method is async. That is why I see my console.log() in this order :
Three
One
Two
How can I do to trigger console.log('Three');
when the Company.find
and Office.find
are finished ?
I want to see the console.log('Three');
at the last position.
Edit :
I think I can do this way :
app.post('/init/autoplete', function(req, res){
var autoplete = {
panies: [],
offices: []
};
// Find all panies
Company.find({}, function(err, panies) {
if (err) throw err;
panies.forEach(function(pany) {
autopletepanies.push({value: pany.name})
});
// Find all offices
Office.find({}, function(err, offices) {
if (err) throw err;
offices.forEach(function(office) {
autoplete.offices.push({value: office.name})
});
res.json(autoplete);
});
});
});
But I don't know if it's the good way. Maybe using promise will be better ? I'm open for all suggestions.
I'm trying to initialize two input with autoplete with this library. When I load my page, I will trigger an Ajax to initialize two input text.
But I don't know how I can detect when all my mongoose find are pleted.
Here is my server side code :
app.post('/init/autoplete', function(req, res){
var autoplete = {
panies: [],
offices: []
};
// Find all panies
Company.find({}, function(err, panies) {
if (err) throw err;
panies.forEach(function(pany) {
autoplete.panies.push({value: pany.name})
});
console.log('One');
});
// Find all offices
Office.find({}, function(err, offices) {
if (err) throw err;
offices.forEach(function(office) {
autoplete.offices.push({value: office.name})
});
console.log('Two');
});
console.log('Three');
// res.json(autoplete);
});
I know than the find method is async. That is why I see my console.log() in this order :
Three
One
Two
How can I do to trigger console.log('Three');
when the Company.find
and Office.find
are finished ?
I want to see the console.log('Three');
at the last position.
Edit :
I think I can do this way :
app.post('/init/autoplete', function(req, res){
var autoplete = {
panies: [],
offices: []
};
// Find all panies
Company.find({}, function(err, panies) {
if (err) throw err;
panies.forEach(function(pany) {
autoplete.panies.push({value: pany.name})
});
// Find all offices
Office.find({}, function(err, offices) {
if (err) throw err;
offices.forEach(function(office) {
autoplete.offices.push({value: office.name})
});
res.json(autoplete);
});
});
});
But I don't know if it's the good way. Maybe using promise will be better ? I'm open for all suggestions.
Share Improve this question edited Sep 13, 2016 at 12:43 John asked Sep 13, 2016 at 12:26 JohnJohn 4,99110 gold badges53 silver badges106 bronze badges 1- use Promise, you can solve paralel and series very easily with Promise – vdj4y Commented Sep 13, 2016 at 13:18
5 Answers
Reset to default 5Mongoose has built-in support for promises which provide a clean way to wait for the pletion of multiple async query operations with Promise.all
:
// Tell Mongoose to use the native Node.js promise library.
mongoose.Promise = global.Promise;
app.post('/init/autoplete', function(req, res){
var autoplete = {
panies: [],
offices: []
};
// Call .exec() on each query without a callback to return its promise.
Promise.all([Company.find({}).exec(), Office.find({}).exec()])
.then(results => {
// results is an array of the results of each promise, in order.
autoplete.panies = results[0].map(c => ({value: c.name}));
autoplete.offices = results[1].map(o => ({value: o.name}));
res.json(autoplete);
})
.catch(err => {
throw err; // res.sendStatus(500) might be better here.
});
});
use Promise. There are ways to control parallel and series. and your code tends to be much readable. My method of dealing with parallel is to execute the async part first, then when the result have been collected, do the synchronous part.
app.post('/init/autoplete', function(req, res){
// Find all panies
// the query action below is not executed, just return PromiseObject for now
var findCompanies = new Promise((resolve, reject) => {
Company.find({}, function(err, panies) {
if (err) reject(err);
resolve(panies)
});
})
// Find all offices
// the query action below is not executed, just return PromiseObject for now
var findOffices = new Promise((resolve, reject) => {
Office.find({}, function(err, offices) {
if (err) reject(err);
resolve(offices)
});
})
// this is the execution part, in OOP world, you can think this is main()
// execute and wait until each action(Promise Object) is plete before finally returning an array.
return Promise.all([findCompanies, findOffices])
.then(array => {
console.log(array) // [ [panies] , [offices] ]
//the difficult async part is done, with just few lines
console.log(array[0]) // [panies] array of panies
console.log(array[1]) // [offices] array of offices
// now you can safely manipulate using forEach.
// basically, this part is for the synchronous action
var autoplete = {};
array[0].forEach(function(pany) {
autoplete.panies.push({value: pany.name})
});
array[1].forEach(function(office) {
autoplete.office.push({value: office.name})
});
res.json(autoplete)
})
});
the code above, findCompanies and FindOffices are Promise Object store in variable(it is not yet executed). Next, with Promise.all(), we run all the Promise Objects, and it will wait until each action is plete before finally returning an array.
the returned array contains another two array. The sequence of this array is the same as the sequence of actions you pass to Promise.all()
if you findOffices first, then findCompanies. It will return [[offices],[panies]]
Promise.all([findOffices, findCompanies])
will return [[offices], [panies]]
vice versa
Promise.all([findCompanies, findOffices])
will return [[panies], [offices]]
With Promises you'll have a more clear code to maintain with not so much overhead, using Mongoose you have two options. Using the native Mongoose promises which is fine for basic use cases. But Mongoose promises are deprecated at this time as a warning will show up.
So to switch to native Promises:
// Native JS Promise
mongoose.Promise = global.Promise;
Or to the more advanced Bluebird Promise library:
// Bluebird
mongoose.Promise = require('bluebird');
An MVCE with native JS promises and Bluebird mented out.
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const assert = require('assert');
mongoose.connect("mongodb://localhost:33023/test_1");
// Native JS Promise
mongoose.Promise = global.Promise;
// Bluebird
// mongoose.Promise = require('bluebird');
// Schema creation
var Company = mongoose.model('Company', new Schema({
name: String
}));
var Office = mongoose.model('Office', new Schema({
name: String
}));
var acme = new Company({
name: 'ACME'
});
var HR = new Office({
name: 'Human Resources'
});
acme
.save()
.then(HR.save());
var query = Company.find({});
assert.equal(query.exec().constructor, global.Promise);
// assert.equal(query.exec().constructor, require('bluebird'));
query.exec()
.then(function(results) {
console.log(results);
})
.then(Office.find({})
.then(function(results) {
console.log(results);
}));
Documentation for Mongoose Promises.
The method you specified can be used but for a large number of async operation, it will result in callback from hell. In order to avoid this it is always better to write code in a sequential and orderly manner. In your case you can use a library like async to achieve this, since mongoose doesn't return a Promise Object
. You can refer to this link for more information on async library.
async.series([
function(callback) {
// do some stuff ...
console.log('one');
callback(null, 'one');
},
function(callback) {
// do some more stuff ...
console.log('two');
callback(null, 'two');
}
],
// optional callback
function(err, results) {
// results is now equal to ['one', 'two']
console.log('three');
});
The third log will only be written once tasks one and two are pleted. series
function runs tasks one by one. You can use the eachSeries to run all tasks parallely.
I'm quite new to mongoose but I just had a similar problem and I solved it by using a cursor()
let cursor = Company.find().cursor();
cursor.on('data', function(doc){
//do something with doc
})
cursor.on('close', function() {
console.log("done");
})
本文标签: javascriptNodejs detect when two mongoose find are finishedStack Overflow
版权声明:本文标题:javascript - Node.js detect when two mongoose find are finished - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741333194a2372884.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论