Nodejs+Mongoose : find and update - node.js

I'm trying to search for a document in my mongo database then using the found document data to search another document and then update both. First document is to be saved after the second document is found.
But with my code the first document saves but doesnot saves updated data
My code :
var posts = {};
Posts.findOne({'url': req.body.url}, function(err, data){
posts = data;
//console.log(data);
Comments.findOne({'bucket': posts.bucket}, function(err, data){
var comment= data;
if(data.count>10){
posts.bucket = posts.bucket +1;
comment.bucket = comment.bucket +1;
}
comment.save(function(err, data){
if(err)
throw err;
});
});
posts.save(function(err, data){
if(err)
throw err;
res.json(data);
});
});
I observed that whatever changes is done in posts variable in Comments.findOne({...}) it remains local to it and doesnot effect outer posts varible, but it is just declared once. so how can i do this. Is something wrong in code? How do I do this!

First document is to be saved after the second document is found.
In your code you're saving the comment and the post in a parallel manner, you need to save the post after saving the document :
var posts = {};
Posts.findOne({
'url': req.body.url
}, function(err, data) {
posts = data;
//console.log(data);
Comments.findOne({
'bucket': posts.bucket
}, function(err, data) {
var comment = data;
if (data.count > 10) {
posts.bucket = posts.bucket + 1;
comment.bucket = comment.bucket + 1;
}
comment.save(function(err, data) {
if (err)
throw err;
posts.save(function(err, data) {
if (err)
throw err;
res.json(data);
});
});
});
});
Another important remark: you're creating a callback hell which leads to unknown behavior later. Please use async or promises instead of nesting callbacks.

Related

Node.js function nested in callback returning not defined error

I'm currently working on a route the returns an array which contains the results from two separate calls to the database. Individually the functions I call in the model functions work as intended. However, when I attempt to combine them by calling the second function within the callback of the first I receive an error that the second function "is not a function". Here is the code in my list route. Note util and errorhandler are files I've created to help with the return format and shouldn't be effecting this error. Any help solving this would be appreciated, Thank you!
route/list
router.route("/list/:id").get(function(req, res) {
list.getListMovie(req.params.id, function(err, list) {
if (err) {
res.json(errorHandler.handleDatabaseErrors(err));
return;
}
var response = [];
response["movies"] = list;
console.log(response)
list.getListTV(req.params.id, function(err, list1) {
if (err) {
res.json(errorHandler.handleDatabaseErrors(err));
return;
}
response["tv"] = JSON.parse(list1);
console.log(response)
res.json(utils.returnFormatForDB(response));
});
});
});
the function definitions within models/list
exports.getListTV = function(userid, done) {
db.get().query('SELECT `idmedia`, `rating`, `title`, `poster_path` FROM
`list` JOIN `tv` ON list.idmedia = tv.tv_id WHERE list.idusers = ?', userid,
function(err, rows) {
if (err) return done(err);
done(null, rows);
});
}
exports.getListMovie = function(userid, done) {
db.get().query('SELECT `idmedia`, `rating`, `title`, `poster_path` FROM
`list` JOIN `movies` ON list.idmedia = movies.movie_id WHERE list.idusers =
?', userid, function(err, rows) {
if (err) return done(err);
done(null, rows);
});
}
EDIT:: I'm not sure of the proper way to mark a question as answered but by fixing the list override and making response an object I was able to get my code to work. Thanks for the help!
You are overwriting the list variable. Try
list.getListMovie(req.params.id, function(err, movieList) {
if (err) {
res.json(errorHandler.handleDatabaseErrors(err));
return;
}
var response = {};
response["movies"] = movieList;
console.log(response)
list.getListTV(req.params.id, function(err, tvList) {
if (err) {
res.json(errorHandler.handleDatabaseErrors(err));
return;
}
response["tv"] = JSON.parse(tvList);
console.log(response)
res.json(utils.returnFormatForDB(response));
});
});
Also, I'm pretty sure you want the response variable to be an object, not an array.

Duplicate mongoose Documents

I'm looking for a very simple way to duplicate a document in my DB but can't find a way to do it.
I have 2 models with the exact same schema.
What i'm doing is
1stDB.findOne({id:"1"}, function(error, results){
if(!error){
var 2ndb = new 2nDB(results);
2nd.save(function (err) {
if (err) {
return err;
}
else {
console.log("SUCCESSFULL");
}
});
}
})
There seems to be an issue as in my console results is formatted properly but just wont save.
But if i do it manually : 2ndb.anyfield = anyvalue it works.
I think it might have to do with promise ? but i'm not very familiar with the concept and might be wrong.
I've tried this :
1stDB.findOne({id:"1"}, function(error, results){
if(!error){
var 2ndb = new 2nDB(**{results}**);
2nd.save(function (err) {
if (err) {
return err;
}
else {
console.log("SUCCESSFULL");
}
});
}
})
and this ( In the hope that deleting the _id and keeping my custom .id field to identify similar document but still having an uniq _id by document would work but it didn't )
1stDB.findOne({id:"1"}, function(error, results){
if(!error){
**var objectResponse = results;
delete objectResponse._id;**
var 2ndb = new 2nDB(results);
2nd.save(function (err) {
if (err) {
return err;
}
else {
console.log("SUCCESSFULL");
}
});
}
})
You can use the following to achieve the required results
1stDB.findOne({id:"1"}).lean().exec(function(error, results){
if(!error){
var objectResponse = results;
delete objectResponse._id;
var 2ndb = new 2nDB(objectResponse);
2nd.save(function (err) {
if (err) {
return err;
}
else {
console.log("SUCCESSFULL");
}
});
}
})
If the lean option is not used, mongoose will return a mongoose object instead of a simple json. This is why you were not able to pass the result directly to the constructor of the 2nd schema. Using the lean query the response will be a plain JSON object which can be passed to the constructor of the 2nd schema. For more information check this stackoverflow post on returning a plan object as response from mongoose

Mongoose not updating the MongoDB document

Here is the nodejs code I'm using to update the document in the mongoDB, req.body contains the document which was send as an post request to the nodejs server,
it is not throwing any errors but not updating the document too, any suggestions why this is happening;
router.route('/results').post(function(req,res){
var toupdate = req.body;
delete toupdate._id;
console.log(toupdate)
Question.update({_id:req.body._id}, toupdate, function(err){
if(err){
console.error(err.stack);
}
});
// even tried Question.update({_id:req.body._id}, {$set:{questions:toupdate.question}});
});
I also tried using findById and then saving the document this time got 500 as an response:
router.route('/results').post(function(req,res){
var toupdate = req.body;
delete toupdate._id;
console.log(toupdate)
Question.findById(eq.body._id, function (err, tank) {
if (err){
console.log(err.stack);
return handleError(err);
}
toupdate.save(function (err){
if (err){
console.log(err.stack);
return handleError(err);
}
});
});
});
Thanks for the support, tried your solution JohnnyHK but it didn't work, but found a way to update the document, had to assign fields of req.body to the fields of an object, here :
router.route('/results').post(function(req,res){
Question.findOne(req.body._id, function (err, questions) {
if (err) return handleError(err.stack);
questions.question = req.body.question;
questions.options = req.body.options;
questions.difficulty = req.body.difficulty;
questions.type = req.body.type;
questions.answer = req.body.answer;
questions.domainof = req.body.domainof;
questions.topic = req.body.topic;
questions.weightage = req.body.weightage;
questions.created_by = req.body.created_by;
questions.save(function (err){
if (err) return handleError(err.stack);
console.log(questions);
});
});
});

Update an array of documents in Mongoose

How can I update ALL documents in a collection where an attributes value needs to be different (a unique number) for each document?
Below is my current code. This actually seems to update (I don't get an error) but the values in the db are not being updated.
Model.find({}, function (err, docs) {
if (err) {
console.log(err);
};
if(docs && docs.length > 0){
for(var i=0; i<docs.length; i++){
//SET NEW VALUE FOR EACH DOC - VALUE MUST BE UNIQUE TO EACH DOC
docs[i].code = generateRandomCode();
}
// PASS IN ARRAY OF UPDATED DOCS TO BE SAVED
Model.update(docs, function (err, docs) {
if (err) {
console.log(err);
}
if(!err){
req.updatedSuccessfully = true;
}
return next();
});
}
else{
return next();
}
});
Before this I was trying to do something like this:
Model.update({}, { code: generateRandomCode() }, { multi: true }, function (err, numberAffected, raw) {
if (err) return handleError(err);
console.log('The number of updated documents was %d', numberAffected);
console.log('The raw response from Mongo was ', raw);
});
The problem with this is that generateRandomCode() is only called once but I need to create a different code for each document. So neither of these example work.
Instead of trying model.update(), can you try to simply save the documents?
See answer to this question on this url: Update model with Mongoose, Express, NodeJS

Get empty Array in first loading page

When I call below function and show data at view of my ejs. There is no data at the first time of loading after the server start. But can get datas from second times of loading. That just only empty list on first time of loading after the server start. What is this matter? I am using redis as database. I also faced same error in using postgreSQL and sovled with
client.on('end', function(){
fn(_datas);
}.
but can't use that code now.
getAllDatas = function(fn){
client.smembers('db:contact:all', function(err, _uid){
if(err)
throw err;
else{
for(var i = 0; i < _uid.length; i++){
client.hgetall('db:contact:' + _uid[i], function(err, reply){
if(err)
throw err;
else{
_datas.push(reply);
}
});
}
}
});
fn(_datas);
_datas = [];
};
I solved as the below code by using setTimeout function. I know that is not the great answer but now can solved my error indeed.
getAllDatas = function(fn){
var _datas = [];
client.smembers('db:contact:all', function(err, _uid){
if(err)
throw err;
else{
for(var i = 0; i < _uid.length; i++){
client.hgetall('db:contact:' + _uid[i], function(err, reply){
if(err)
throw err;
else{
_datas.push(reply);
}
});
}
}
});
setTimeout(function(){
fn(_datas);
}, 100);
};

Resources