Hi I have this code but when finish the result is not the espected because didn't run in the sequence that I wish
here is the code:
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
var req_games = [];
if (!err) {
for (var i in games) {
req_games.push(games[i]);
models.users.findOne({_id: games[i].w_id}, function (err, user) {
req_games[i].w_id = user.user;
console.log(req_games[i].w_id) //< -- 3
});
console.log('a ' + req_games[i].w_id) //<-- 2
}
user_data.games = req_games; // <-- 1
}
});
at the end of the task req_games didnt have any update because it's running in the sequence that I put in the comments in the code
This may help you using Q(promises)
obj.find = function(model, condition) { //make your find to return promise
var deferred = q.defer();
model.find(condition, function(err, results) {
if (err) {
logger.log(err);
deferred.reject(err);
} else {
deferred.resolve(results);
}
});
return deferred.promise;
}
ArraysOfId.forEach(function (id) {
var tempProm = mongoUtilsMethodObj.find(schemaObj.Asset, id).then(function (assetObj) {
---- your code
return q.resolve();
});
promArr.push(tempProm);//push all promise to array
});
q.all(promArr).then(function () {
// this will be called when all promise in array will we resolved
})
Here is a version using the async library to map your game values.
var async = require('async');
var user_data = {};
models.games.find({$or: [{w_id: req.user._id}, {b_id: req.user._id}, {owner: req.user._id}]}, function (err, games) {
if(err) {
// or whatever your error response happens to be
return res.render('user.swig', {error: err});
}
async.map(games, function(game, nextGame) {
models.users.findOne({_id: game.w_id}, function (err, user) {
game.w_id = user.user;
nextGame(err, game);
});
}, function(err, req_games) {
user_data.games = req_games;
res.render('user.swig', {user: user_data});
});
});
Related
Hello I am having an issue with the following sequence, I need to run multiple queries which build on each other that are in a for loop then once the final result is obtained to implement the result. I am having an issue where my for loop is looping past the query, also I need to stop the code while the findX function is running.
I know this is an async problem but I don't see how I could chain promises, or use the async npm package with needing to loop queries that depend on the result of the previous query. Thanks in advance.
function findX(){
//executes another query
}
function solve(res, connection, info, requestArr, callback){
var parentID = null;
var obj = {};
for (var i = 0; i <= requestArr.length; i++) {
connection.query("SELECT WHERE ", [parentID, requestArr[i]], function(err, results) {
if(results[0]['x']){
var obj = findX(x)
break;
}else{
parentID = results[0]['parentID'];
}
});
}
//Do stuff with obj only after the final result has been set in the for loop
}
You can use Async TimesSeries.
// Pretend this is some complicated async factory
var createUser = function(id, callback) {
callback(null, {
id: 'user' + id
});
};
// generate 5 users
async.times(5, function(n, next) {
createUser(n, function(err, user) {
next(err, user);
});
}, function(err, users) {
// we should now have 5 users
});
So, in your example would be something like this:
var iterations = requestArr.length - 1,
parentID,
obj;
var getResults = function (i, callback) {
connection.query("SELECT WHERE ", [parentID, requestArr[i]], function (err, results) {
if (results[0]['x']) {
obj = findX(x);
callback('done');
}
else {
parentID = results[0]['parentID'];
callback();
}
});
};
async.timesSeries(iterations, function (n, next) {
getResults(n, function (err) {
next(err);
});
}, function (err) {
// use obj
});
var shortLinks = [];
Link.find({}, function (err, links) {
if (err) {
console.log(err);
} else {
links.map(link => {
shortLinks.push(link.shortLink);
});
}
console.log(shortLinks);//shortLinks has values, all okey
});
console.log(shortLinks); //shortLinks is empty
i need to use shortLinks after Link.find({}) but array is empty.
Need to return shortLinks.
Callbacks. The function(err, links) is called asynchronously, so shortLinks isn't populated until that function is called. Your bottom console.log is being called first, due to how callbacks work.
https://developer.mozilla.org/en-US/docs/Mozilla/js-ctypes/Using_js-ctypes/Declaring_and_Using_Callbacks
need to use promise:
const shortLinks = [];
const getShortLinks = Link.find({}, function (err, links) {
if (err) {
console.log(err);
} else {
links.map(link => {
shortLinks.push(link.shortLink);
});
}
});
getShortLinks.then(function(links){
console.log(shortLinks);
}, function(err){
console.log(err);
});
It turns a funny error in Node.js mongodb, if I put the form below:
locals.collection.find(filter, req.query);
returns me the following error:
MongoError: query selector must be an object
Now if I manually put the query works.
I'm having this problem a long time, and I've tried several ways.
locals.collection.find({slug:'somak'}, req.query);
I am using the following function:
exports.findAll = function(req, res, next) {
var locals = {},
section = req.params.section,
query = req.query,
filter = {};
if(query.filter) {
filter = query.filter.replace(/"(\w+)"\s*:/g, '$1:');
filter = filter.replace(/["]/g, "'");
}
console.log(filter);
delete query.filter;
async.series([
function(callback) {
MongoClient.connect(url, function(err, db) {
if (err) return callback(err);
locals.collection = db.collection(section);
callback();
});
},
function(callback) {
locals.collection.count(filter, function (err, result){
if (err) return callback(err);
locals.count = result;
callback();
});
},
function(callback) {
var cursor = locals.collection.find({slug:'somak'}, req.query);
if(req.query.page) {
cursor = cursor.skip(Math.abs(req.query.limit) * --req.query.page);
}
cursor.toArray(function(err, docs) {
if (err) return callback(err);
locals.docs = docs;
callback();
});
}
],
function(err) { //This function gets called after the three tasks have called their "task callbacks"
if (err) return next(err);
// Here locals will be populated with 'count' and 'docs'
res.json({
count: locals.count,
data: locals.docs
});
});
Just use JSON.parse:
exports.findAll = function(req, res, next) {
var locals = {},
section = req.params.section,
query = req.query,
filter = {};
if(query.filter) {
filter = JSON.parse(query.filter);
}
delete query.filter;
...
I am writing the filter using mongodb native driver, but it's driving me this error when you run the query.
In the case of this driver, it has no exec?
What is another way to perform this query?
exports.findAll = function(req, res) {
MongoClient.connect(url, function(err, db) {
var section = req.params.section;
var collection = db.collection(section);
var filter = req.query.filter ? {nameToLower: new RegExp('^' + req.query.filter.toLowerCase())} : {};
var query = collection.find(filter);
var count = 0;
collection.count(filter, function (error, result) {
count = result;
});
if(req.query.order) {
query.sort(req.query.order);
}
if(req.query.limit) {
query.limit(req.query.limit);
if(req.query.page) {
query.skip(req.query.limit * --req.query.page);
}
}
query.exec(function (error, results) {
res.json({
count: count,
data: results
});
});
});
};
Error:
TypeError: undefined is not a function
Better to use the async library in this case as it simplifies the code. In the case where you need to run multiple tasks that depend on each other and when they all finish do something else, use the
async.series() module. The following demonstrates how you can go about this in your case:
exports.findAll = function(req, res) {
var locals = {},
section = req.params.section,
filter = !!req.query.filter ? {nameToLower: new RegExp('^' + req.query.filter.toLowerCase())} : {};
async.series([
// Connect to DB
function(callback) {
MongoClient.connect(url, function(err, db) {
if (err) return callback(err);
locals.collection = db.collection(section); //Set the collection here, so the next task can access it
callback();
});
},
// Get count
function(callback) {
locals.collection.count(filter, function (err, result){
if (err) return callback(err);
locals.count = result; //Set the count here
callback();
});
},
// Query collection
function(callback) {
var cursor = locals.collection.find(filter);
if(req.query.order) {
cursor = cursor.sort(req.query.order);
}
if(req.query.limit) {
cursor = cursor.limit(req.query.limit);
if(req.query.page) {
cursor = cursor.skip(req.query.limit * --req.query.page);
}
}
cursor.toArray(function(err, docs) {
if (err) return callback(err);
locals.docs = docs;
callback();
});
}
], function(err) { //This function gets called after the three tasks have called their "task callbacks"
if (err) return next(err);
// Here locals will be populated with 'count' and 'docs'
res.json({
count: locals.count,
data: locals.docs
});
res.render('user-profile', locals);
});
};
When I run collection.find() in MongoDB/Node/Express, I need to return value for my array like this but iam in callback hell;
foursquare.getVenues(params,function(error, venues) {
if (!error) {
var places = [];
venues.response.venues.forEach(function(e) {
places.push(
{
obj_id:e.id,
name:e.name,
distance:e.distance,
here_now:req.collection.findById(e.id) //count- i want need this value
}
);
});
res.send(places);
}
});
You can try to use Async https://github.com/caolan/async#each
var async = require('async');
...
foursquare.getVenues(params, function (error, venues) {
if (!error) {
throw err;
}
var places = [];
async.each(venues.response.venues, function (e, callback) {
db.collection.findById(e.id, function (err, res) {
places.push({
obj_id: e.id,
name: e.name,
distance: e.distance,
here_now: res
});
callback()
});
}, function (err) {
if (err) {
console.log('A file failed to process');
} else {
console.log('All files have been processed successfully');
res.send(places);
}
});
});
or Using async.map
var async = require('async');
var createArray = function (e, cb) {
db.collection.findById(e.id,function(err,res){
var obj = {
obj_id: e.id,
name: e.name,
distance: e.distance,
here_now: res
}
cb(null, obj);
});
}
async.map(venues.response.venues, createArray, function (err, places) {
if(err){
throw err;
}
console.log(places);
});