Unable to equate id's of two object in nodejs to the objects returned from mongodb - node.js

Here is the code snipped which runs when I open a webpage from browser, it queries all the users, and just removes the users object who is querying it.
I am trying to do it by equating their _id's field which is generated by default in mongodb and is always unique, I am able to print each object's _id field but when i try it in if condition it fails to enter the if condition,
user.find({}, { 'local.name': 1, route_id: 1, stop_number: 1, _id: 1 }, function (err, allusers) {
if (err) throw err;
var len = allusers.length;
for (var index = 0; index < len; index++) {
console.log(allusers[index]._id);
console.log(index);
if (allusers[index]._id === req.user._id) {
console.log("here");
allusers.splice(index, 1);
}
}
res.send(allusers);
})
Here is the output of above:
GET /javascripts/delete_user.js 304 1ms
588f2aded1902a1b08959145
0
58bd116c84fdb70a9c4f34aa
1
can't figure where I am going wrong, and yes, req.user._id equals to the first user's id i.e. 588f2aded1902a1b08959145, still does not enters if condition, if someone can please point me in the right direction.

Try
if( allusers[index]._id.toString() === req.user._id.toString() ) {
console.log("here");
allusers.splice(index,1);
}
Works for me :)

I found the solution to the error, I was removing the object as soon as I found it, which was reducing the length of allusers array and when it will try to reach last index which is now undefined as I spliced it already it was reading the -id property of undefined.
Here is the correct code:
user.find({}, { 'local.name': 1, route_id: 1, stop_number: 1, _id: 1 }, function (err, allusers) {
if (err) throw err;
var len = allusers.length;
var to_remove;
for (var index = 0; index < len; index++) {
if (allusers[index]._id === req.user._id) {
to_remove = index;
}
}
allusers.splice(to_remove, 1);
res.send(allusers);
})

Related

Can't update variable value in mongoose find method

I am trying to update a variable's value in the findById mongoose method. The code looks like this:
let todayIncome = 0;
// Loop through all id's and add the price value to todayIncome
for(let i = 0; i < priceIDs.length; i++) {
Prices.findById({ _id: priceIDs[i] }, (err, data) => {
todayIncome += data.price;
console.log("INCOME: ", todayIncome) // Output is 40 which is correct
});
}
console.log("Income: ", todayIncome); // Output is 0
// Return dayIncome a json
res.json({
data: todayIncome // Output is 0
});
Why can't the value be saved in the variable outside of the findById method am I missing something? Help would be appreciated!

Synchronous for loop in node js

So let's say I have the following for loop
for(var i = 0; i < array.length; i++){
Model.findOne({ _id = array[i].id}, function(err, found){
//Some stuff
});
}
How do I make this code work? Every time I run it I get array[i] = undefinedbecause the mongo-db query is asynchronous and the loop has already iterated 5 times by the time the first query is even completed. How do I go about tackling this issue and waiting for the query to complete before going on to the next iteration?
This doesn't specifically answer your question, but addresses your problem.
I'd use an $in query and do the filtering all at once. 20 calls to the db is pretty slow compared to 1:
// grab your ids
var arrayIds = myArray.map(function(item) {
return item._id;
});
// find all of them
Model.find({_id: {$in: arrayIds}}, function(error, foundItems) {
if (error) {
// error handle
}
// set up a map of the found ids
var foundItemsMap = {};
foundItems.forEach(function(item) {
foundItemsMap[item._id] = true;
});
// pull out your items that haven't been created yet
var newItems = [];
for (var i = 0; i < myArray.length; i++) {
var arrayItem = myArray[i];
if ( foundItemsMap[arrayItem._id] ) {
// this array item exists in the map of foundIds
// so the item already exists in the database
}
else {
// it doesn't exist, push it into the new array
newItems.push(arrayItem);
}
}
// now you have `newItems`, an array of objects that aren't in the database
});
One of the easiest ways to accomplish something like you want is using promises. You could use the library q to do this:
var Q = require('q');
function fetchOne(id) {
var deferred = Q.defer();
Model.findOne({ _id = id}, function(err, found){
if(err) deferred.reject(err);
else deferred.resolve(found);
});
return deferred.promise;
}
function fetch(ids, action) {
if(ids.length === 0) return;
var id = ids.pop();
fetchOne(id).then(function(model) {
action(model);
fetch(ids, action);
});
}
fetch([1,2,3,4,5], function(model) { /* do something */ });
It is not the most beautiful implementation, but I'm sure you get the picture :)
Not sure if this is the right way, it could be a bit expensive but this how i did it.
I think the trick is to pull all your data and then looking for an id match.
Model.find(function(err, data) {
if (err) //handle it
for (var i=0; i<array.length; i++) {
for (var j=0; ij<data.length; j++) {
if(data[j].id == array[i].id) {
// do something
}
}
}
}

Asynchronous Iteration of Array of JSON

I'm using Node.js with MongoDB, to be more specific, MongoLab and Mongoose.
In the DB, I have two collections, pours and users. A user object would be linked to multiple pour objects with a shared cid.
I need to iterate through an array of user objects. But for loop somehow doesn't work with asyn functions that I would like to use to modify my array.
express.leaderboard = new Array();
mongoose.Users.find(function(err, users) {
for (var i = 0; i < users.length; i++) {
express.leaderboard[express.leaderboard.length] = users[i];
};
for (i = 0; i < express.leaderboard.length; i++){
updateOunces(i, function(a, fluidOunces){
console.log(a);
express.leaderboard[a].set('totalOunces', fluidOunces);
});
}
});
And this is my function that would retrieve the total fluidOunces for a user.
function updateOunces(i, callback){
//console.log(express.leaderboard[b].cid);
mongoose.Pours.find({
"cid": express.leaderboard[i].cid
}).exec(function(err, result) {
var userOunces = 0.0;
if (!err) {
for (i = 0; i < result.length; i += 1) {
for(j = 0; j < result[i].pour.length; j += 1){
userOunces += result[i].pour[j].fluidOunces;
}
}
callback(i, userOunces);
return;
express.leaderboard[i].set ('totalOunces' , userOunces);
} else {
console.log(err)
};
});
};
Is there a way to iterate and add a new property to each object in the leaderboard array? Using ASYN? Thank you!
use async library.
Example)
mongoose.Users.find(function(err, users) {
async.each(users, function(user, callback) {
// perform updates here, per user.
callback();
}, function(err) {
// everything is complete.
});
});

While loop to check uniqueness of custom id

I have a MongoDB databse set up with some objects that have a unique code (not the primary key).
I should also note that I'm using NodeJS and this code is in my server.js to connect to the MongoDB database.
To generate a new code, I generate one randomly and I want to check if it already exists. If not then we use it no problem, but if it already exists I want to generate another code and check it again. This is the code I use to check if the id already exists:
function createPartyId(callback) {
var min = 10000, max = 99999;
var partyId = -1, count = -1;
async.whilst(
function () { return count != 0; },
function (callback) {
partyId = min + Math.floor(Math.random() * (max - min + 1));
partyId = 88888;
getPartyIdCount(partyId, function(num) {
count = num;
});
},
function (err) {
}
);
}
function getPartyIdCount(partyId, callback) {
count = -1;
db.db_name.find({id: partyId}, function(err, records) {
if(err) {
console.log("There was an error executing the database query.");
callback(count);
}
count = records.length;
callback(count);
});
}
First of all, is there any particular reason you're not using a simple number increment sequence? This type of code is prone to inefficiency, the more numbers you generate the more chance you have of collisions which means you're going to be spending more time on generating an ID for your data than you are on the rest of your processing. Not a good idea.
But I can still tell you what's going wrong.
OK, so getPartyIdCount() will only, ever, always, without fail, return undefined (or, basically, nothing).
Your mongo call processes the return value in a callback, and that callback doesn't assign its value to anything, so return records.length just gets lost into nothingness.
You've mixed up createPartyId(), which it appears you want to run synchronously, with your mongo call, which must run asynchronously.
return always goes with the nearest containing function, so in this case it goes with function(err, records), not function getPartyIdCount(partyId).
(Expanding my comment from above)
The issue is that createPartyId is an asynchronous function, but you're trying to return the value synchronously. That won't work. Once you touch an async operation, the rest of the call stack has to be async as well.
You don't include the code that's calling this, but I assume you want it to be something like:
var partyId = createPartyId();
// do stuff...
That's not going to work. Try this:
function createPartyId(callback) {
var min = 10000, max = 99999;
var partyId = -1, count = -1;
async.whilst(
function () { return (count == 0); },
function (callback) {
partyId = min + Math.floor(Math.random() * (max - min + 1));
partyId = 88888;
getPartyIdCount(partyId, function(err, num) {
if (!err) {
count = num;
}
callback(err);
});
},
function (err) {
// this is called when the loop ends, error or not
// Invoke outer callback to return the result
callback(err, count);
}
);
}
function getPartyIdCount(partyId, callback) {
count = -1;
db.db_name.find({id: partyId}, function(err, records) {
if(err) {
console.log("There was an error executing the database query.");
callback(err);
}
count = records.length;
callback(null, count);
});
}
(I've also adopted the default node.js convention of always returning errors as the first argument to callback functions.)
So, to use this you would do:
getPartyId(function (err, num) {
if (err) { return aughItFellOver(err); }
// do stuff
});

How to properly save array of objects with mongoose + nodejs?

I have an array of names:
var names = ["Kelley", "Amy", "Mark"]
Assuming Person is just a Mongoose model for nodejs... I want to save each name as a document into mongodb with the following:
for(var i = 0; i < names.length; i++) {
name_now = names[i];
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);
}
}
)
}
I am having issues as I keep geting a "Error creating schedule: MongoError: E11000 duplicate key error index:..... dup key: {: "Mark"}". And it appears that it is trying to insert "Mark" (the last element in the list) 3 times as opposed to each of the names in the list.
When I try to print out the name of the current person in the loop (with the console.log(personDoc.name);), I get "Mark" 3 times... and it appears that it only saved "Mark" in the database and no one else... what is the proper way to deal with this?
During the findOne callbacks, name_now is always going to be set to the last name in names because the for loop completes before the first callback is even called. You need to create an immediate function to capture the current name_now value during each iteration and preserve it for use in the callback:
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]);
}

Resources