How to perform forloop in node js - node.js

Acoording to the data available ui should get 2 reults but getting only one since i put res.send in the looop so it is getting ended ,can anyone help me out please.......
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
} else {}
});
}
res.send(resp);
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}

The problem is in getting the profiles. You are using mongodb's find which is asynchronous. Therefore in your for cycle you start fetching the profiles, but then you send out the res.send well before the fetching of the profiles is finished.
The call back from profile.find(... will be executed after the res.send. Apart from this, the resp variable is inside the find callback and you are trying to res.send it outside.
To deal with this, either you use async or promises. See the below code that uses promises.
var Promise = require('bluebird')
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
var profiles_to_get = []
var profiles = []
for (var i in result) {
var id = result[i].recieved_id;
profiles_to_get.push(get_profile(id, profiles))
}
Promise.all(profiles_to_get)
.then(() => {
res.send(profiles);
})
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
function get_profile (id, profiles) {
return new Promise(function (resolve, reject) {
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
reject(err)
return
}
if (resp) {
profiles.push(resp)
resolve()
} else {
reject()
}
});
})
}
}
How this works is that it creates a list of profiles to find and stores it in the var profiles_to_get = []. The you use Promise.All(profiles_to_get) which will let you do stuff after all the profiles have been fetched.

You can send only one response back to a request.
Define a variable outside the for loop, append records to it and then send it after the for loop has ended.
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
var resList = [];
record.find(item).toArray((err, result) => {
if (err) {
return
}
if (result) {
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return
}
if (resp) {
console.log(resp);
resList[i] = resp;
}
else{
}
});
}
}//end of if loop
else {
resList = {
status: 'fail',
data: []
};
}
res.send(resList);
});

Don't use for loop in asynchronous mode. Use async module instead like below.
var async = require('async');
exports.getrequestsdetails = function (req, res) {
var params = req.params;
console.log(params)
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
}
record.find(item).toArray(function (err, result) {
if (err) {
return
}
if (result) {
var list = [];
async.each(result, function (item, cb) {
var id = item.recieved_id;
var profile = db.collection('profile');
profile.findOne({
'_id': new ObjectId(id)
}, function (err, resp) {
if (err) {
return cb();
}
if (resp) {
list.push(resp);
console.log(resp);
return cb();
}
return cb();
});
}, function (err) {
res.send(list);
});
}//end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
}

You can push all the resp in list array and send after completing loop.
Like this:
exports.getrequestsdetails = function(req, res) {
var params = req.params;
console.log(params);
var record = db.collection('requests');
var item = {
"sent_id": params.id,
"status": 1
};
record.find(item).toArray((err, result) => {
if (err) {
return err;
}
if (result) {
var list = [];
for (var i in result) {
var id = result[i].recieved_id;
var profile = db.collection('profile');
profile.find({
'_id': new ObjectId(id)
}).toArray((err, resp) => {
if (err) {
return err;
}
else{
list.push(resp);
console.log(resp);
if(i===result[result.length-1]){
res.send(list);
}
}
});
}
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
});
};
Hope this work for you

You can add all the list in to an array and finally send the data after the loop

Related

Express mongoose Query cannot set headers

Does anyone know why this code gives me the error: "Cannot set headers after they are sent to the client"?
Is there something wrong with my Mongoose Queries?
Thanks for your help!!
router.post('/setriskbydate', (req, res) => {
var username = req.body.username;
var from = new Date(req.body.from);
var to = new Date(req.body.to);
var dates = getDates(from, to);
User.findOne({ username: username }, (err, resp) => {
if (err) {
res.send(err);
}
if (resp) {
var rideIds = resp.ride;
for (let i = 0; i < rideIds.length; i++) {
Ride.findOne({ _id: rideIds[i] }, (error, response) => {
if (error) {
res.send(error)
}
if (response) {
var busnumber = response.busnumber
var date = response.date.split('T')[0];
if (dates.includes(date)) {
console.log(response);
Ride.updateMany({ busnumber: busnumber, date: { "$regex": date }}, { risk: "high" }, (er, re) => {
if (er) {
res.send(er);
}
if (re) {
res.send(re);
}
})
}
}
})
}
}
})
})
Make sure to return all your response statements so that the responses aren't sent more than once, including the headers which cannot be set again after a response.
return res.send(err);
...
return res.send(re);
I think I got it.. Because I am in a for loop I cant do res.send() because the function terminates then. I just replaced the last res.send() with something else and it worked.

Mongoose .select is not a function when using with Azure Function

I'm trying to use mongoose .select operator with my azure function but it keeps saying TypeError: db.collection(...).findOne(...).select is not a function at db.collection.find.toArray
It returns the user's data in the console, but doesn't filter it down with .select
Why is that?
var MongoClient = require('mongodb').MongoClient;
var Post = require('./model/post');
var mongoose = require('mongoose');
module.exports = async function (context, req) {
let currentPage = 1;
MongoClient.connect(process.env.CosmosDBConnectionString, async (err, client) => {
let send = response(client, context);
if (err) send(500, err.message);
let db = client.db(process.env.dbName);
await db.collection('listings').find(
{
$and: [
{ winnerHasBeenNotified: false },
{ auctionEndDateTime: { $lte: Date.now().toString() } }
]
}
)
.toArray((err, result) => {
console.log("result");
console.log(result);
if (result) {
for (let i = 0; i < result.length; i++) {
db.collection('users').findOne(
{
_id: mongoose.Types.ObjectId(result[i].bidderId)
}
).select("notificationBy").toArray((err, result) => {
console.log("USER RESULT!");
console.log(result);
});
}
}
if (err) send(500, err.message);
send(200, JSON.parse(JSON.stringify(result)));
});
});
};
function response(client, context) {
return function (status, body) {
context.res = {
status: status,
body: body
};
client.close();
context.done();
};
}
find() returns a cursor, which has a select method. findOne() retrieves a single document and returns a promise if no callback is provided.
If you are trying to get just the "notificationBy" field, try passing the fields option to findOne.

promise all not working as expected while working with list

I want the callback to return the response when promise all finishes. I am getting the response before promise all. Batch List is empty in response, as it is returned before promise all.
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err) {
reject();
} else {
resolve();
}
});
}).then(async () =>
{
requestList = requestList.concat(results.items);
const runAsyncFunctions = async () => {
var promises = [];
requestList.map(async request => {
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
promises.concat(promise);
});
await Promise.all(
promises
).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey
};
callback("", response);
}).catch((error) => {
console.log(error);
});
};
await runAsyncFunctions();
}).catch((error) => {
callback(error, response);
});
}
promises is not an array of promises.
The line
var promise = await this.getBatchList(request.requestID.S, mode, null, null, function(err, result) {
batchList = batchList.concat(result.items);
});
is executed later then
callback("", response)
I guess you want to do something like this
var promises = [];
for (const request of requestList) {
const promise = this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
batchList = batchList.concat(result.items);
});
promises.push(promise);
}
await Promise.all(
...
The correct way of doing it is:
getByReferenceID(object, mode, limit, lastEvaluatedKey, callback){
var results = {};
var requestList = [];
var batchList = [];
var response = {};
new Promise((resolve, reject) => {
this.getRequestList(object, limit, lastEvaluatedKey,function (err, result) {
console.log(result);
results = result;
if(err){
reject(err);
}
else{
resolve();
}
});
return results;
}).then(() =>
{
requestList = requestList.concat(results.items);
var iteration =0;
new Promise((resolve, reject) => {
for (let request of requestList) {
console.log(request.requestID.S);
this.getBatchList(request.requestID.S, mode, null, null, function (err, result) {
iteration++;
batchList = batchList.concat(result.items);
if(iteration === requestList.length)
{
resolve();
}
if(err)
{
reject();
}
});
}
}).then(()=>{
response = {
"requests": requestList,
"batches": batchList,
"lastEvaluatedKey": results.LastEvaluatedKey,
};
callback("", response);
}).catch((error) => {
callback(error, response);
});
}).catch((error) => {
callback(error, response);
});
}

How to use promises in mongoose

By runnig the below code,i can see the values in my console,but the response i got is empty ,i thoink it may be because of promises....
My code,
exports.getcatlist = function(req, res) {
var params = req.params,
item = {
'status': '1',
'type': 'categories'
};
Categories.find(item,function (err, result) {
if (err) {
return
}
if (result) {
var profiles = [];
var categories_to_get = []
var categories = []
for (var i in result) {
var id = result[i]._id;console.log(id)
var id = id.toString();
categories_to_get.push(get_category(id, profiles))
}
Promise.all(categories_to_get)
.then(() => {
console.log('final vals'+categories_to_get)
res.json({status: 'success', data: profiles});
})
} //end of if loop
else {
response = {
status: 'fail',
data: []
};
}
})
function get_category(id, profiles) {
var profiles = [];
return new Promise(function (resolve, reject) {
var item = {
'categoryid' : id,
'status': '1',
'type': 'topics',
};
Categories.count(item,function (err, result) {
if (err) {
reject(err)
return
}
if (result == []) {
profiles.push(result)
resolve()
}
if (result) {
profiles.push(result)
resolve()
} else {
reject()
}
});
})
}
}
By runnig the above code,i can see the values in my console,but the response i got is empty
`{
"status": "success",
"data": []
}`
I am not sure why i am getting my data as empty,can anyone please suggest help...
Sorry but your code is pretty messy, here's solution and clean approach, i would strongly suggest to use async library for things you tryin to accomplish.
//npm install async --save
var async = require('async');
exports.getcatlist = (req, res) => {
var params = req.params;
Categories.find({
status: '1',
type: 'categories'
}, (err, result) => {
if(err)
return res.json({status: 'fail'});
var profiles = [];
async.each(result, (id, cb) => {
Categories.count({
categoryid: id,
status: '1',
type: 'topics'
}, (ierr, val) => {
if(ierr)
return cb(ierr);
profiles.push(val);
cb();
});
}, (eachError) => {
if(eachError)
return res.json({status: 'fail'});
res.json({status: 'success', data: profiles});
});
}
}

how to run code sequentially in node js

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

Resources