Delete from mongoDB by id - node.js

I would like to delete an item from my database using the id I passed to it, not by the object ID. How do I do this?
I have done some reading on deleteOne but I'm not quite sure how to go about putting it into use.
Each movie has a button to delete a movie so I need the id of each movie to be passed into the remove function. New to MERN stack here.
{
"_id": "5fa55741aae528142e96c9e6",
"id": 531219,
"user": "5fa406cf937ce199eeb176a1",
"title": "Roald Dahl's The Witches",
"overview": "large string ... ",
"poster_path": "/betExZlgK0l7CZ9CsCBVcwO1OjL.jpg",
"vote_average": "7.1",
"__v": 0
},
My code so far
router.delete('/:id/delete', auth, async (req, res)=>{
const movie = await Movie.findByIdAndRemove(req.body.id)
if(!movie){
res.send('Movie not found')
} else{
movie.remove()
res.send('movie deleted')
}
})
case REMOVE_MOVIE:
return{...state, wishlist:state.wishlist.filter(movie => movie.id !== payload)}
export const removeMovie = (id) => async dispatch => {
try {
await axios.delete(`/wishlist/${id}/delete`)
dispatch({
type: REMOVE_MOVIE,
payload:id
})
} catch (error) {
console.log('unable to delete movie')
console.error(error)
}
}

Your problem is findByIdAndRemove() looks for the _id and you want to use other value to execute the query. So you can use findOneAndDelete() function from Mongoose.
There are also more functios to do the job as deleteOne or findAndDelete. But if you want to delete by id I recommend use findOneAndDelete because return the deleted document.
Then you have to pass the id to query like this:
var deleted = await model.findAndDelete({id: "myID"})
Note that id is not the same as _id.
And that's all...
From documentation, to know how functions works:
findOneAndDelete()
Deletes a single document based on the filter and sort criteria, returning the deleted document.
deleteOne
Removes a single document from a collection.
And also, if you are using mongoose and you want delete by _id you can use findByIdAndDelete() function instead of findByIdAndRemove().
According to documentation
This function differs slightly from Model.findOneAndRemove() in that findOneAndRemove() becomes a MongoDB findAndModify() command, as opposed to a findOneAndDelete() command. For most mongoose use cases, this distinction is purely pedantic. You should use findOneAndDelete() unless you have a good reason not to.

I was able to remedy this issue using the advice above, but I needed to capture and assign the value of the movie being clicked on to the id value passed into findOneAndDelete. I did this by passing in req.params.id. So it was findOneAndDelete({id: req.params.id}). Now everything works as expected. Thanks!

Related

Express, Mongoose, db.findOne always returns same document

I am attempting a CRUD app with MEAN stack. I am using mongoose in Express to call to the MongoDB. I am using the FindOne function with a specified parameter, and it's always returning the same (incorrect) document.
I know I am connected to the correct database, since I get a document back from that collection, but it's always the same document, no matter what I pass as the parameter.
module.exports = mongoose.model('Player', playersSchema, 'players'); //in player.js
const Player = require('./model/players');
app.get('/api/player/:id', (req, res) =>{
Player.findOne({id: req.params.playerId},
function(err, player) {
if(err) {
res.json(err);
}
else {
res.json(player);
}
});
});
I have 3 separate "players", with three distinct "playerID" fields (38187361, 35167321, 95821442). I can use Postman to GET the following URL, for example:
http://localhost:3000/api/player/anythingyouWantInHere
and it will return 38187361, the first document. I've been over this website, many tutorials, and the Mongoose documentation and I can't see what I'm doing wrong..
I'd like to eventually find by playerId OR username OR email, but one hurdle at a time...
From the mongoose documentation of findOne, if you pass Id a null or an empty value, it will query db.players.findOne({}) internally which will return first document of the collection everytime you fetch. So make sure you are passing non-empty id here.
Note: conditions is optional, and if conditions is null or undefined,
mongoose will send an empty findOne command to MongoDB, which will
return an arbitrary document. If you're querying by _id, use
findById() instead.
Your route is '/api/player/:id', so the key on the req.params object will be 'id' not 'playerId'.
I don't know what/where/if you're populating the playerId param, but if you update your query to call req.params.id it should actually change the document based on the path as you seem to be wanting to do.
I had the same problem, and it was that the name of column's table was different from the model I had created.
In my model the name of the wrong column was "role" and in my table it was "rol".

Mongoose display comments and stars(likes) for each post [duplicate]

In Mongoose, I can use a query populate to populate additional fields after a query. I can also populate multiple paths, such as
Person.find({})
.populate('books movie', 'title pages director')
.exec()
However, this would generate a lookup on book gathering the fields for title, pages and director - and also a lookup on movie gathering the fields for title, pages and director as well. What I want is to get title and pages from books only, and director from movie. I could do something like this:
Person.find({})
.populate('books', 'title pages')
.populate('movie', 'director')
.exec()
which gives me the expected result and queries.
But is there any way to have the behavior of the second snippet using a similar "single line" syntax like the first snippet? The reason for that, is that I want to programmatically determine the arguments for the populate function and feed it in. I cannot do that for multiple populate calls.
After looking into the sourcecode of mongoose, I solved this with:
var populateQuery = [{path:'books', select:'title pages'}, {path:'movie', select:'director'}];
Person.find({})
.populate(populateQuery)
.execPopulate()
you can also do something like below:
{path:'user',select:['key1','key2']}
You achieve that by simply passing object or array of objects to populate() method.
const query = [
{
path:'books',
select:'title pages'
},
{
path:'movie',
select:'director'
}
];
const result = await Person.find().populate(query).lean();
Consider that lean() method is optional, it just returns raw json rather than mongoose object and makes code execution a little bit faster! Don't forget to make your function (callback) async!
This is how it's done based on the Mongoose JS documentation http://mongoosejs.com/docs/populate.html
Let's say you have a BookCollection schema which contains users and books
In order to perform a query and get all the BookCollections with its related users and books you would do this
models.BookCollection
.find({})
.populate('user')
.populate('books')
.lean()
.exec(function (err, bookcollection) {
if (err) return console.error(err);
try {
mongoose.connection.close();
res.render('viewbookcollection', { content: bookcollection});
} catch (e) {
console.log("errror getting bookcollection"+e);
}
//Your Schema must include path
let createdData =Person.create(dataYouWant)
await createdData.populate([{path:'books', select:'title pages'},{path:'movie', select:'director'}])

findOne - 'Specify the Fields to Return' does not work? [duplicate]

I'm pretty new with mongo and nodejs
I've a json as result of my query and I simply want to return the result as an http request, as following:
app.get('/itesms', function(req, res) {
items.find().toArray(function (err, array) {
res.send(array);
})
});
It works, only problem is that I want to hide the _id fields (recursively) from the result.
Any suggestion to do that in an elegant way?
Try this solution:
app.get('/itesms', function(req, res) {
items.find({}, { _id: 0 }).toArray(function (err, array) {
res.send(array);
})
});
The usual .find({}, {_id:0}) approach wasn't working for me, so I went hunting and found in another SO answer that in version 3 of the Mongo API, you need to write it like this: .find({}, {projection:{_id:0}}). So, for example:
let docs = await db.collection("mycol").find({}, {projection:{_id:0}}).toArray();
It seems that (in the nodejs API, at least) you can also write it like this:
let docs = await db.collection("mycol").find({}).project({_id:0}).toArray();
The problem is that you can't project inclusions and exclusions, ie you can't run a query with a 'project' statement that declares what should be included in the response as well as what must be excluded from the response.
From MongoDB documentation:
A projection cannot contain both include and exclude specifications, except for the exclusion of the _id field. In projections that explicitly include fields, the _id field is the only field that you can explicitly exclude.
The way I handled this problem was to go to the end of the process, right before returning the response:
const dbObjectJSON = dbObject.toJson();
delete dbObjectJSON._id;
delete dbObjectJSON.__v;
...
response.json(dbObjectJSON);
Hope this helps.

Update multiple documents and return all updated documents

I am looking for a way to update many documents at once using mongoose and return all the modified documents. I tried with setting multi:true in update(). It is updating all matching documents but not returning any. Then I tried with findOneAndUpdate(). It is updating and returning only one document even if there are many matching ones. Yeah, the function name itself tells, it will update only one, still I tried. I could not set option like multi:true in findOneAndUpdate(). How can it be done? Thanks in advance
Currently I don't think its possible in MongoDB to update multiple documents and return all the updated documents in the same query.
In Mongoose, the findOneAndUpdate() is based on the native findAndModify() method of MongoDB.
If you check the offical documentation of the findAndModify() method, its states that -
The findAndModify command modifies and returns a single document.
Although the query may match multiple documents, findAndModify will only select one document to modify.
Hence, you can not update multiple documents using findAndModify.
update() or updateMany() method on the other hand updates many documents with the multi flag but it only returns the WriteResult which looks like this -
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
I know, I'm too let, but I also face this same requirement as yours,
Here is what I apply in Controller to get the requirement done as yours by NodeJs...
export const updateManyData = async (req, res) => {
try {
const updateAllData = await Model.updateMany({} , {$set: {status: "active"}});
const sendToClient = await Model.find();
console.log(updateAllData); // => just updated status is here
console.log(sendToClient); // your all updated result is here
res.send('Update Many Post Successful!');
} catch (error) {
res.status(500).send('Server Side Error');
}
}
First upate and then get as per Jyotmans answer.
const update = await Model.updateMany({
condition: "value"
}, {
"$set": {
field: "value"
}
}, {
"multi": true
});
// res.json(icMessages)
const get = await Model.find({
room: req.params.room
}).exec()
res.json(get)

remove _id from mongo result

I'm pretty new with mongo and nodejs
I've a json as result of my query and I simply want to return the result as an http request, as following:
app.get('/itesms', function(req, res) {
items.find().toArray(function (err, array) {
res.send(array);
})
});
It works, only problem is that I want to hide the _id fields (recursively) from the result.
Any suggestion to do that in an elegant way?
Try this solution:
app.get('/itesms', function(req, res) {
items.find({}, { _id: 0 }).toArray(function (err, array) {
res.send(array);
})
});
The usual .find({}, {_id:0}) approach wasn't working for me, so I went hunting and found in another SO answer that in version 3 of the Mongo API, you need to write it like this: .find({}, {projection:{_id:0}}). So, for example:
let docs = await db.collection("mycol").find({}, {projection:{_id:0}}).toArray();
It seems that (in the nodejs API, at least) you can also write it like this:
let docs = await db.collection("mycol").find({}).project({_id:0}).toArray();
The problem is that you can't project inclusions and exclusions, ie you can't run a query with a 'project' statement that declares what should be included in the response as well as what must be excluded from the response.
From MongoDB documentation:
A projection cannot contain both include and exclude specifications, except for the exclusion of the _id field. In projections that explicitly include fields, the _id field is the only field that you can explicitly exclude.
The way I handled this problem was to go to the end of the process, right before returning the response:
const dbObjectJSON = dbObject.toJson();
delete dbObjectJSON._id;
delete dbObjectJSON.__v;
...
response.json(dbObjectJSON);
Hope this helps.

Resources