remove _id from mongo result - node.js

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.

Related

Delete from mongoDB by id

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!

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.

How to return multiple Mongoose collections in one get request?

I am trying to generate a response that returns the same collection sorted by 3 different columns. Here's the code I currently have:
var findRoute = router.route("/find")
findRoute.get(function(req, res) {
Box.find(function(err, boxes) {
res.json(boxes)
}).sort("-itemCount");
});
As you can see, we're making a single get request, querying for the Boxes, and then sorting them by itemCount at the end. This does not work for me because the request only returns a single JSON collection that is sorted by itemCount.
What can I do if I want to return two more collections sorted by, say, name and size properties -- all in the same request?
Crete an object to encapsulate the information and chain your find queries, like:
var findRoute = router.route("/find");
var json = {};
findRoute.get(function(req, res) {
Box.find(function(err, boxes) {
json.boxes = boxes;
Collection2.find(function (error, coll2) {
json.coll2 = coll2;
Collection3.find(function (error, coll3) {
json.coll3 = coll3;
res.json(json);
}).sort("-size");
}).sort("-name");
}).sort("-itemCount");
});
Just make sure to do the appropriate error checking.
This is kind of uggly and makes your code kind of difficult to read. Try to adapt this logic using modules like async or even promises (Q and bluebird are good examples).
If I understand well, you want something like that : return Several collections with mongodb
Tell me if that helps.
Bye.
Have you tried ?
Box.find().sort("-itemCount").exec(function(err, boxes) {
res.json(boxes)
});
Also for sorting your results based on 2 or more fields you can use :
.sort({name: 1, size: -1})
Let me know if that helps.

Resources