mongoose - model.update not working - node.js

I'm doing a simple update when my node.js app receives a certain POST request. This is my code:
app.post('/comment', function (req,res) {
var params = req.body;
BlogPost.update({"title": params.title}, {$push: { comments: {author : params.author, content: params.content, date: new Date().toUTCString()}}});
res.redirect('back');
});
where BlogPost is a mongoose Model. (This model works when querying for documents).
Now the problem is, when I do subsequent queries, nothing happens. For example, running the above code for a document with "title" "aaa" (which is supposed to push an object to the array "comments", querying for that document with title "aaa" returns something like
{ _id: 51954d4663aa986aa93a734f,
title: 'aaa',
comments: [] }
Anything I'm doing really wrong?

You should add a callback to get the error message.
I was having a similar issue and simply adding the callback, everything was working fine, even with an empty callback.
Try:
app.post('/comment', function (req,res) {
var params = req.body;
BlogPost.update({"title": params.title}, {$push: { comments: {author : params.author, content: params.content, date: new Date().toUTCString()}}},function(error){console.log(error);});
res.redirect('back');
});

This is such strange behavior by mongoose. I also had this and since update() is deprecated I used updateOne() instead, but it too only works when adding the callback function.

Related

500 (Internal Server Error) when retrieving one document from MongoDB without using _id

I am using MEAN stack (my first project) and I don't find the solution to successfully request a single element from MongoDB. The page that I am describing is opened when a user wants to edit an item out of a given list on the main page. My aim is, that the information of the clicked item (from the main page) is displayed on the edit-page.
These are the relevant lines from the server.js:
mongoose.connect("mongodb://localhost:27017/item_list", {useNewUrlParser: true, useCreateIndex: true});
<...>
const itemSchema = new mongoose.Schema({id: {type: Number, required: true},
text: {type: String, required: true}
});
<...>
//get single item from db
app.get('/item/:id', async (request, response) => {
try{
var result = await Item.findById( {id: request.params.id} ).exec();
response.send(result);
}catch(error){
response.status(500).send(error);
}});
In the service module, I am using the following function to call the API:
getItem(id: number): Observable<Item> {
const url = '/item/'+id;
return this.http
.get<Item>(url)
.pipe(catchError(this.handleError<Item>(`getItem id=${id}`)));
}
In the typescript file of the "output"-module I am using the following function:
#Input() item: Item;
getItem(): void {
const id = +this.route.snapshot.paramMap.get('id');
this.itemService.getItem(id)
.subscribe(item => this.item = item);
}
The route contains the (unique) id of the item, that I assigned to it - it is the id with which my request queries the database.
Here the code snippet of the link from the main page that leads to the Edit-page:
<a routerLink="/edit-item/ {{item.id}}">Edit</a>
However, I am receiving an Internal Server Error. I believe, that the problem is the method ".findById({...})" in the server.js. I have other requests that are working (e.g. retrieving the whole item list), so the database connection is working fine. Any hints are very much appreciated!
findById is a method on the model to find a document by its _id.
You can look into documentation here.
Replace the line as follows to make it work
var result = await Item.findById( {_id: request.params.id} ).exec();
If you need to find by a different custom Id and want to query a single document then use findOne as documented here

Looking for Best Approach For update one in Mongoose

I am still kind of new to Mongoose in general. I am building my blogging app which has backend based on Node and MongoDB, I am using Angular for frontend.
I am creating my Restful API which is supposed to allow user click on a post and update it. However, I don't know for sure whether I am doing it the right way here.
This is the schema for my post:
const mongoose = require('mongoose');
// Schema Is ONly bluePrint
var postSchema = mongoose.Schema({
title: {type: String, required: true },
content: {type: String, required: true},
}, {timestamps: true});
module.exports = mongoose.model("Post", postSchema);
In my angular service, I have this function to help me to send the http request to my backend server, the id for this function comes from backend mongoDB, title and content is from the form on the page
updatePost(id: string, title: string, content: string) {
console.log('start posts.service->updatePost()');
const post: Post = {
id: id,
title: title,
content: content
};
this._http.put(`http://localhost:3000/api/posts/${id}`, post)
.subscribe(res => console.log(res));
}
It appears to me that there are at least couple of ways of approaching this for creating my API
Method 1 ( works but highly doubt if this is good practice):
here I am passing the id retrieved from mongoDB back to server via my service.ts file to avoid the 'modifying immutable field _id' error
app.put("/api/posts/:id", (req,res)=>{
console.log('update api called:', req.params.id);
const post = new Post({
id: req.body.id,
title: req.body.title,
content: req.body.content
});
Post.updateOne({_id: req.params.id}, post).then( result=> {
console.log(result);
res.json({message:"Update successful!"});
});
});
Method 2 I consider this is more robust than method 1 but still I don't think its good practice:
app.put("/api/posts/:id", (req, res)=> {
Post.findOne(
{_id:req.params.id},(err,post)=>{
if(err){
console.log('Post Not found!');
res.json({message:"Error",error:err});
}else{
console.log('Found post:',post);
post.title=req.body.title;
post.content=req.body.content;
post.save((err,p)=>{
if(err){
console.log('Save from update failed!');
res.json({message:"Error",error:err});
}else{
res.json({message:"update success",data:p});
}
})
}
}
);
});
I am open to all opinions in the hope that I can learn something from guru of Mongoose and Restful : )
Justification to Choose findOneAndUpdate() in this scenario in simple words are as follow:
You can use findOneAndUpdate() as it updates document based on the
filter and sort criteria.
While working with mongoose mostly we prefer to use this function as compare to update() as it has a an option {new:
true} and with the help of that we can get updated data.
As your purpose here is to updating a single document so you can use findOneAndUpdate(). On the other hand update() should be
used in case of bulk modification.
As update() Always returns on of document modified it won't return updated documents and while working with such a scenario like
your we always returns updated document data in response so we
should use findOneAndUpdate() here

Mongo / Express Query Nested _id from query string

Using: node/express/mongodb/mongoose
With the setup listed above, I have created my schema and model and can query as needed. What I'm wondering how to do though is, pass the express request.query object to Model.find() in mongoose to match and query the _id of a nested document. In this instance, the query may look something like:
http://domain.com/api/object._id=57902aeec07ffa2290f179fe
Where object is a nested object that exists elsewhere in the database. I can easily query other fields. _id is the only one giving an issue. It returns an empty array of matches.
Can this be done?
This is an example and not the ACTUAL schema but this gets the point across..
let Category = mongoose.Schema({
name: String
})
let Product = mongoose.Schema({
name: String,
description:String,
category:Category
})
// sample category..
{
_id:ObjectId("1234567890"),
name: 'Sample Category'
}
// sample product
{
_id:ObjectId("0987654321"),
name:'Sample Product',
description:'Sample Product Description',
category: {
_id:ObjectId("1234567890"),
name: 'Sample Category'
}
}
So, what I'm looking for is... if I have the following in express..
app.get('/products',function(req,res,next){
let query = req.query
ProductModel.find(query).exec(function(err,docs){
res.json(docs)
})
})
This would allow me to specify anything I want in the query parameters as a query. So I could..
http://domain.com/api/products?name=String
http://domain.com/api/products?description=String
http://domain.com/api/products?category.name=String
I can query by category.name like this, but I can't do:
http://domain.com/api/products?category._id=1234567890
This returns an empty array
Change your query to http://domain.com/api/object/57902aeec07ffa2290f179fe and try
app.get('/api/object/:_id', function(req, res) {
// req._id is Mongo Document Id
// change MyModel to your model name
MyModel.findOne( {'_id' : req._id }, function(err, doc){
// do smth with this document
console.log(doc);
});
});
or try this one
http://domain.com/api/object?id=57902aeec07ffa2290f179fe
app.get('/api/object', function(req, res) {
var id = req.param('id');
MyModel.findOne( {'_id' : id }, function(err, doc){
console.log(doc);
});
})
First of all increase your skills in getting URL and POST Parameters by this article.
Read official Express 4.x API Documentation
Never mind I feel ridiculous. It works just as I posted above.. after I fixed an error in my schema.

nodeJS + MongoDB + Mongoose - Unable To Delete 1 Entry

I'm using nodeJS MongoDB/Mongoose to create/update/delete movies inside the database using Postman post/delete methods.
The create function is working fine, and even the remove function is working properly so when I use Postman I get the return: "Movie has been deleted!" like it should.
The only problem is that my function is emptying the entire database of movies instead of just that 1 movie, here is the remove function:
function destroy(req, res, next){
var movieID = req.body
Movie.remove(movieID, function(err,movie){
if(err){
res.status(400).send(err)
} else {
res.send("Movie has been deleted!")
db.close()
}
})
The movie object:
var movieSchema = new mongoose.Schema({
name: String,
yay: Number,
nay: Number,
release_date: Date,
in_theaters: Boolean,
released: Boolean,
buy_link: String,
imdb_link: String,
image_url: String,
description: String,
trailer_link: String
})
I want to delete a movie based on it's "name" so I only have to input the name and it will delete the entire movie.
Have you tried the findOneAndRemove query?
This query is much cleaner compared to finding a model and removing it inside the callback. Beside this I assume it's faster because you basically do 1 query instead of 2 after each other.
If you are passing direct value to Remove method, it will try to match with _id field.
As per your model, _id is ObjectId field which is managed automatically by mongodb.
In case if you enter like this. .remove("movie", callback) which is not a valid ObjectId.
Mongoose is discarding this invalid condition and executing Movie.remove({}); which is deleting all your records.
So it is better to validate whether the input is valid ObjectId or not before directly passing to Movie.remove();
I also recommend to use like this: Movie.remove({_id: movieId}, callback).
And for movie name :
Movie.remove({name: movieName}, callback);
Update:
You can take from Postman
var movieName = req.body.movieName;
Movie.remove({name: movieName}, function(err, updateObj){
});
Can you try this?
var movieName = req.body.name;
Movie.find('name': movieName, function(err, movie) {
if (err) res.send({error: err});
Movie.remove(function(err, movie){
if (err) res.send({error: err});
res.json({message: "Movie is removed", movie: movie});
});
});

Cannot Read property '_id' of undefined while using mongoose findOneandUpdate

I am using mean.io to make sports event management system.I am trying to update a model Player with rest api and it throws this error from mongoose:
{ _id: 5411c79895d600440c698fa1,
email: 'abc#bcd.com',
name: 'James Bond',
username: 'james.bond',
games: [ 5411bd54786cfe2420f1e27a ],
teams: [],
roles: [ 'authenticated' ] }
[TypeError: Cannot read property '_id' of undefined]
PUT /api/players/5411c79895d600440c698fa1 500 199.402 ms - 36
I also tried to delete the _id proterty from player but it doesnot works either.
the method i have used to update the model player is :
exports.update = function(req, res) {
var player = req.player;
player = _.extend(player, req.body);
console.log(player);
Player.findOneAndUpdate(req.params.playerId, player,{new:true}, function (err, updatedPlayer) {
console.log(err);
if (err) {
return res.status(500).json({
error: 'Cannot update the player'
});
}
res.json(updatedPlayer);
});
And also if i used the model.save method provided in the default package article of mean.io, it shows another error. I have extended the user model in player package app.js file. So whenever I try to update one field, the field that I have declared in app.js are required and the path required error from mongoose is thrown.
You have two issues in your update request.
First, the findOneAndUpdate expects a dict as the query and not just the id, so you should give it {_id: req.params.playerId} instead.
Second, passing a mongoose object as the update data is risky, instead you should convert it to a dict like this var _player = player.toObject() and then have _player be passed to the update request. Remember that you need to remove the _id param of_player because you can't change the _id of a document. Before doing the update just do delete _player._id and you should be fine. Also, new is set to true by default so you won't need the options dict.
Here is your working code:
var player = _.extend(req.player, req.body);
var _player = player.toObject();
delete _player._id;
var query = {_id: req.params.playerId};
Player.findOneAndUpdate(query, _player, function (err, updatedPlayer) {
...
});
But in this case you shouldn't even have to do the first operation. Since you just want to update the data of req.body you can do:
var query = {_id: req.params.playerId};
var data = {
$set: req.body,
};
Player.findOneAndUpdate(query, data, function (err, updatedPlayer) {
...
});
This will update all the fields of the player matching the query with the values from req.body.

Resources