Unable to find record by id in mongoose - node.js

I am trying to find record by id but it not getting done
var id = req.param('id');
var item = {
'_id': id
}
videos.find(item, function(error, response) {});
I have give a valid id but still it is not fetching,can anyone suggest help,please.

There is a callback provided to find() but in your code above, it has no executable statements. Instead of this:
videos.find(item, function(error, response) {});
...do something like this:
videos.find(item, function(error, response) {
if (error) {
console.log(error); // replace with real error handling
return;
}
console.log(response); // replace with real data handling
});

You have to use callbacks for error handling. And find() returns array. If you need to find user by unique key (in this case _id) you must use findOne()
router.get('/GetVideoByID/:id',function(req,res){
var id = req.params.id;
var video = {
'_id' : id
}
videos.findOne(video,function(err,data){
if(err){
console.log(err);
}else{
console.log("Video found");
res.json(data);
}
});
});

Related

Cannot set headers after they are sent to clients in node.js

My code is not working . I am beginner and don't know my problem. Kindly help.I have seen one or two solution on stackoverflow but didnot get .
This is code.
app.post('/post',(request,response)=>{
var description=request.body.description;
var contact_number=request.body.contact_number;
var city=request.body.city;
var budget=request.body.budget;
var category=request.body.optradio;
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
response.send("successful");
});
response.redirect('/data');
});
app.get('/data',function(request,response){
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC",(err, rows,fields) => {
if(err) {
console.log(err);
}
else {
response.render('feed', {title : 'Jobs Details',
items: rows })
}
});
});
app.listen(3000);
This is the error
pp.post('/post', (request, response) => {
var description = request.body.description;
var contact_number = request.body.contact_number;
var city = request.body.city;
var budget = request.body.budget;
var category = request.body.optradio;
var query = connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)", [null, description, category, city, contact_number, budget],
function (err) {
if (err) {
console.log(err);
} else {
response.redirect('/data');
}
});
});
app.get('/data', function (request, response) {
connection.query("SELECT * FROM jobs ORDER BY Jobs_id DESC", (err, rows, fields) => {
if (err) {
console.log(err);
}
else {
response.render('feed', {
title: 'Jobs Details',
items: rows
})
}
});
});
app.listen(3000);
There can be only one response to single HTTP request. In your code, you are first trying to send response with
response.send("successful");
but this on its own doesn't break the flow of the function which means that if the condition is actually met then this will execute and the execution continues and finds another response, in this case
response.redirect('/data');
and it will try to send another response to the original http request but at this point it is already too late because one response has already been send.
To solve this issue in general, you can place return in front of any line of code that is closing the the connection (response.send, response.redirect, ...). That way, the function's execution is terminated at the first response, whichever it is.
So you could do something like
var query=connection.query("insert into jobs(Jobs_id,Description,Category,City,Contact_number,Budget) values(?,?,?,?,?,?)",[null,description,category,city,contact_number,budget],function(err){
if(err)
console.log(err);
else
return response.send("successful");
});
return response.redirect('/data');
});

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

Pass model object to mongoose request

I would like to save an object from one schema to the array in another one. What I have is User schema and Events schema. User schema has, for example, a property "joined" which is array. When making put request, meeting should be pushed to "joined" array.
At the moment I have this code on clientside:
<div ng-repeat="event in events">
...
<button ng-click="joinEvent(event)">Join</button>
</div>
$scope.joinEvent = function(event){
$http.put('/join', event)
.success(function (data) {
$scope.users = data;
})
.error(function (data) {
console.log('Error: ' + data);
})
};
and this this in express.js routes:
app.put('/join', function (req, res){
var user = req.user; // logged in user
var id = req.user._id;
var update = { $addToSet: {joined: req.event} };
User.findByIdAndUpdate(id, update, {upsert: true}, function (err, user) {
if (!err) {
console.log("joined");
//return all users from db
User.find(function(err, users) {
if (err)
res.send(err)
res.json(users);
});
} else {
if(err.name == 'ValidationError') {
res.statusCode = 400;
res.send({ error: 'Validation error' });
} else {
res.statusCode = 500;
res.send({ error: 'Server error' });
}
console.log('Internal error(%d): %s',res.statusCode,err.message);
}
});
});
After all, I see 'null' in user.joined. What's wrong with my approach?
The way you're trying to get the event name is wrong.
In your code, req.event == null . That's why you see null in 'user.joined'.
In the client - event property should look like this:
event = {eventName: "someEventName"}
In the server - you reach to event name like this:
var update = { $addToSet: {joined: req.body.eventName} };
Thanks to Yarden for pushing me into the right direction. I made it in other way by passing event id on clientside and making Event.findById query before looking for user. That worked.

How to I get the results of a call to a method that is located in a Mongoose model?

How can I get the results of a method that I have defined inside a Mongoose model. I pass a parameter to the method. Here is what I have tried:
mySchema.methods.getStuff = function(id) {
return this.model('coolSchema')
.findOne({ _id : id })
.exec(function (err, data) {
console.log(data); // I can see that the data is retrieved
return data;
})
};
I then try to call this method by doing the following:
var cool = new coolSchema();
cool.getStuff(id, function (err, data) {
console.log(data); // data is not being passed here as expected
});
What am I doing wrong?
Your schema method should have a callback argument, and call it with the results of the query. The way it is written here you are just returning a query. The callback function you pass as 2nd arg to getStuff is never looked at by that method.
Something like this should work out:
mySchema.methods.getStuff = function(id, cb) { // <-- note getStuff takes a callback arg now
return this.model('coolSchema')
.findOne({ _id : id })
.exec(function (err, data) {
if (err) cb(err); // check for errors
console.log(data); // I can see that the data is retrieved
cb(null, data); // <-- call the callback with the results
})
};
I assume you left off for brevity but it's also a good idea to check undefined/null id and that cb is actually callable.
You can also use a promise library to make a promisified version of the model:
var Promise = require('bluebird');
mySchema = Promise.promisify(mongoose.model('mySchema'));
Then in your schema method use the Async versions of the regular methods:
mySchema.methods.getStuff = function(id, cb) {
return this.model('coolSchema')
.findOneAsync({ _id : id }) // <-- using 'promisified' version of method
.then(function (id) {
if (!id) throw new Error('ID wasn't found!')
return id;
})
.catch(function(e){
// db was down, etc. try to handle, or rethrow
console.log('db error');
})
};
then call then:
cool.getStuff(id).then(function (data) {
console.log(data);
})
.catch(function(e){}
console.log('Error: ' + e.message);
);

Partial update of a subdocument with nodejs/mongoose

Is it possible to set multiple properties on a (sub)document in one go with Mongoose? An example of what I'm trying to do:
Let's say I have this schema:
var subSchema = new Schema({
someField: String,
someOtherField: String
});
var parentSchema = new Schema({
fieldOne: String,
subDocs: [subSchema]
})
Then I would like to do:
exports.updateMyDocument = function(req, res) {
var parentDoc = req.parentDoc; // The parent document. Set by parameter resolver.
var document = req.myDoc; // Sub document of parent. Set by parameter resolver.
var partialUpdate = req.body; // updated fields sent as json and parsed by body parser
// I know that the statement below doesn't work, it's just an example of what I would like to do.
// Updating only the fields supplied in "partialUpdate" on the document
document.update(partialUpdate);
parentDoc.save(function(err) {
if(err) {
res.send(500);
return;
}
res.send(204);
});
};
Normally, I could achieve this using the $set operator, but my problem is that document in this example is a subdocument (embedded schema) of parentDoc. So when I tried to do
Parent.update({_id: parentDoc._id, "subDocs._id": document._id},
{$set: {"subDocs.$" : partialUpdate}},
function(err, numAffected) {});
it replaced the subdocument instance identified by subDocs._id. Currently I have "solved" it by setting only fields manually, but I was hoping for a better way to do this.
Build up a $set object programmatically based on the fields of partialUpdate to update just those fields using dot notation:
var set = {};
for (var field in partialUpdate) {
set['subDocs.$.' + field] = partialUpdate[field];
}
Parent.update({_id: parentDoc._id, "subDocs._id": document._id},
{$set: set},
function(err, numAffected) {});
I've done different, in a REST application.
First, I have this route:
router.put('/:id/:resource/:resourceId', function(req, res, next) {
// this method is only for Array of resources.
updateSet(req.params.id, req.params.resource, req, res, next);
});
and the updateSet() method
function updateSet(id, resource, req, res, next) {
var data = req.body;
var resourceId = req.params.resourceId;
Collection.findById(id, function(err, collection) {
if (err) {
rest.response(req, res, err);
} else {
var subdoc = collection[resource].id(resourceId);
// set the data for each key
_.each(data, function(d, k) {
subdoc[k] = d;
});
collection.save(function (err, docs) {
rest.response(req, res, err, docs);
});
}
});
}
The brilliant part is mongoose will validate the data if you define the Schema for this subdocument. This code will be valid for any resource of the document that is an Array. I'm not showing all my data for simplicity, but is a good practice to check for this situations and handle the response error properly.
You can assign or extend embedded document.
Doc.findOne({ _id: docId })
.then(function (doc) {
if (null === doc) {
throw new Error('Document not found');
}
return doc.embeded.id(ObjectId(embeddedId));
})
.then(function(embeddedDoc) {
if (null === embeddedDoc) {
throw new Error('Embedded document not found');
}
Object.assign(embeddedDoc, updateData));
return embeddedDoc.parent().save();
})
.catch(function (err) {
//Do something
});
And in this case you should be shure that _id is not assigning.
I handled this in a slightly different manner without using the $set object. My approach is similar to Guilherme's but one difference is that I wrapped my method into the statics functionality so that it is easier to re-use throughout my application. Example below.
In CollectionSchema.js server model.
collectionSchema.statics.decrementsubdocScoreById = function decreasesubdoc (collectionId, subdocId, callback) {
this.findById(collectionId, function(err, collection) {
if (err) console.log("error finding collection");
else {
var subdoc = collection.subdocs.filter(function (subdoc) {
return subdoc._id.equals(subdocId);
})[0];
subdoc.score -= 1;
collection.save(callback);
}
});
};
In Server Controller
Collection.decrementsubdocScoreById(collectionId, subdocId, function (err, data) {
handleError(err);
doStuffWith(data);
});

Resources