Node.JS/MongoDB: document join solutions - node.js

I have been trying to do a 3 document join with mongodb and am going around in circles (literally). I am attempting to do this leveraging async inside a loop to grab the additional documents and then build a custom json document that will be passed into my page. I am having limited success with this and am wonder if anyone has tried this or has some suggestions.
MongoClient.connect("mongodb://localhost:27017/preInc", function(err, db) {
if(err) { return console.dir(err); }
var collection = db.collection('resource_Tbl');
collection.find().toArray(function(err, items)
{
if(err) {
return console.dir(err); }
else {
test = items;
}
for (var i = 0; i < items.length; i++)
{
var temp = items[i]._id.toHexString();
var name = items[i].name;
console.dir(temp + "-|-" + name);
Async.waterfall([
function getGeoAddress(callback)
{
console.dir(temp + " " + name);
callback(null, 'unknown');
},
],
function (err, results)
{
if (err)
{
console.log(err);
}
else
{
}
});
}
res.render('heatmap', { data: test, headerX:'preInc.org' });
});
});
});
the main problem I am running into now is that the loop works perfectly but the async does not start until after the loop has finished and only processes the last record (x times)
thank you in advance.
AEgir...

Related

node.js async/sync with For Loop, Query, and Additional function

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

nodeJS Mongoose updating multiple documents & returning the changed values

I'm essentially trying to find all Tasks with a given scaler_ID and then set them their respective scaler_ID to -1 and then return all of the new tasks in the HTTP response.
Here's my code:
api.post('/unassignTasks', function(req, res) {
Task.find({scaler_ID: req.body.scaler_ID}, function(err, tasks) {
for (var i = 0; i < tasks.length; ++i) {
tasks[i].scaler_Id = -1;
console.log(tasks[i]);
(function(arrayIndex) {
tasks[i].save(function(err, result) {
if (err) { console.log(err); }
});
})(i);
res.send(tasks);
return;
}
});
For some reason this won't work and the scaler_ID is not being set to -1 to the elements in the database. Any ideas what is causing this?
Proper way by using async.each
//npm install async --save //don't forget to install it first
var async = require('async');
api.post('/unassignTasks', function(req, res) {
var id = req.body.scaler_ID;
Task.find({scaler_ID: id }, function(err, tasks) {
async.each(tasks, function(task, each_cb) {
task.scaler_Id = -1;
task.save(each_cb);
}, function(err) {
if(err)
return res.status(400).send(err);
res.send(tasks);
});
});
}

Getting empty array because of the asynchronous nature of Nodejs

Just started working with Nodejs and facing this issue while pushing the array as a response in the below code. I know this is happening because of the asynchronous nature of Nodejs, tried to apply async as well but did not get the desired result. Could someone let me know the fix of this code:
array = [];
var company = companySchema.Company;
company.findOne({_id: companySchema.objectId(req.tempStore.companyId)}, function (err, comp) {
if (err) {
console.log(err);
}
else {
var i;
var length = comp.events.length;
var dataset = datasetSchema.dataset;
for (i = 0; i < length; i++) {
dataset.find({companyId:comp.events[i]}, function (err,data) {
if (err) {
console.log(err);
}
else {
array.push(data);
}
console.log("array-----"+array); // prints array here
});
}
}
console.log("array-----"+array); // array is empty hence causing empty response
res.response.data = array;
next();
});
You can use mongoDB $in clause for this task:
var company = companySchema.Company;
company.findOne({_id: companySchema.objectId(req.tempStore.companyId)}, function (err, comp) {
if (err) {
console.log(err);
} else {
var dataset = datasetSchema.dataset;
dataset.find({companyId : {$in : comp.events}}, function (err, docs) {
if (err) {
console.log(err);
} else {
console.log("array: " + docs); // prints array here
res.response.data = docs;
next();
}
});
}
});

Not able to access result returned from mongoDb outside query

I am working with node.js using express and mongoDb.
I am trying to retrieve data from database "local" and collection "borrower" and pushing it into an empty array collectionOne. It is rendering this array on the view page.
I want to use _id pushed in an array b_ids from this output to make a call to company_details collection under same router .
The issue I am facing here is I am not getting any value in array b_ids when trying to access it under call to company_details collection.
The code is as below:
var collectionOne = [];
var collectionTwo = [];
var b_ids = [];
router.get('/fetch',function(req, res, next){
MongoClient.connect('mongodb://localhost:27017/local', function(err, db){
var collection = db.collection('borrower');
db.collection("borrower", function(err, collection) {
collection.find().toArray(function(err, result) {
if (err) {
throw err;
} else {
//console.log(result[0].first_name);
for (i=0; i<result.length; i++) {
collectionOne[i] = result[i];
b_ids[i] = result[i]._id;
}
}
});
db.collection("company_details", function(err, collection){
console.log(b_ids);
collection.find({borrower_id : {$in :b_ids}}).toArray(function(err, result){
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionTwo[i] = result[i];
}
}
});
});
res.render('index',{data : collectionOne , data1 : collectionTwo});
});
});
});
Please suggest me how can I access the b_ids array here. Thanks in advance :)
The callback from toArray is asynchronous, i.e. will happen after your console.log line executes, therefore you need to re-arrange as follows:
var collectionOne = [];
router.get('/fetch',function(req, res, next){
MongoClient.connect('mongodb://localhost:27017/local', function(err, db){
var collection = db.collection('borrower');
db.collection("borrower", function(err, collection) {
collection.find().toArray(function(err, result) {
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionOne[i] = result[i];
b_ids[i] = result[i]._id;
}
db.collection("company_details", function(err, collection){
console.log(b_ids);
collection.find({borrower_id : {$in :b_ids}}).toArray(function(err, result){
if (err) {
throw err;
} else {
for (i=0; i<result.length; i++) {
collectionTwo[i] = result[i];
}
res.render('index',{data : collectionOne , data1 : collectionTwo});
}
});
});
}
});
});
});
This ensures that the callback completes before you try and log / render it.
It is simple create a function with a callback function inside it as an argument
function returnBids(collection, callback){
collection.find().toArray(function(err, result) {
if (err)
throw err;
else
callback(result)
})
}
and you can access your result outside by calling the function returnbids() .i.e
returnBids(collection,function(b_ids){
console.log(b_ids)
})

How to create callback post saving an array of objects?

Assuming I have the following in a function:
exports.addnames = function(req, res) {
var names = ["Kelley", "Amy", "Mark"];
for(var i = 0; i < names.length; i++) {
(function (name_now) {
Person.findOne({ name: name_now},
function(err, doc) {
if(!err && !doc) {
var personDoc = new PersonDoc();
personDoc.name = name_now;
console.log(personDoc.name);
personDoc.save(function(err) {});
} else if(!err) {
console.log("Person is in the system");
} else {
console.log("ERROR: " + err);
}
}
);
)(names[i]);
}
My issue is after I save the names, I want to return the results:
Person.find({}, function(err, doc) {
res.json(200, doc);
})
Though I have a callback for names, it appears that the last block of code (Persons.find({})) gets executed before the calls to save all the names is complete... thusly when the user goes to the url in the browser, "doc" is empty... Is there some way I can ensure that the Persons.find({}) is called after the for loop completes?
The easiest way to do things like this is to use an async library like the aptly named async which can be found at https://github.com/caolan/async.
If you have a list of names that you want to save and then return when complete, it would look like:
// save each of the names asynchronously
async.forEach(names, function(name, done) {
Person.findOne({name: name},
function(err, doc) {
// return immediately if there was an error
if(err) return done(err);
// save the person if it doesn't already exist
if(!doc) {
var personDoc = new PersonDoc();
personDoc.name = name;
console.log(personDoc.name);
// the async call is complete after the save completes
return personDoc.save(done);
}
// or if the name is already there, just return successfully
console.log("Person is in the system");
done();
}
);
},
// this function is called after all of the names have been saved
// or as soon as an error occurs
function(err) {
if(err) return console.log('ERROR: ' + err);
Person.find({}, function(err, doc) {
res.json(200, doc);
})
});

Resources