How to pick a subdocument with its id? - node.js

I'm trying to get a subdocument (nested in array) by its id, but I still get the whole document.
router.get("/book/:libraryid/:bookid", (req, res) => {
Library.findOne({ _id: req.params.libraryid, "book._id": req.params.bookid})
.then(result => {
console.log(result); //shows all subdocument
});
});
How can I just pick out the subdocument with its id?
Schema:
{
"_id": {
"$oid": "12345"
},
"libaryName": "A random libary",
"Books": [
{
"_id": {
"$oid": "1"
}
"bookTitle": "Example",
"TotalPages": "500"
},
{
"_id": {
"$oid": "2"
}
"bookTitle": "Delete Me",
"TotalPages": "400"
}
]
}

Use the following and it should return you the document with only filtered book based on bookId.
router.get("/book/:libraryid/:bookid", (req, res) => {
Library.findOne({ _id: req.params.libraryid}, {"books": {"$elemMatch": {_id: req.params.bookid}}})
.then(result => {
console.log(result); //shows all subdocument
});
});

Related

How to remove an object from array of objects in mongoose?

I have this data and I want to remove a given movie based on its id/title
"_id": "604184234a2f37156cec63ca",
"name": "Jacob Tremblay",
"description": "Jacob Tremblay is a Canadian actor. He made his film debut as Blue in the live action animated film",
"born": "06051993",
"bornCountry": "Usa",
"movies": [
{
"movie": {
"_id": "604184384a2f37156cec63cb",
"title": "Luca",
"__v": 0,
"id": "604184384a2f37156cec63cb"
},
"role": "Luca"
}
],
"__v": 0
}
In documentation it says I can achieve this using the $pull, but im having trouble to figure it out how its done. My controller method
const removeMovieForActor = async (req, res, next) => {
try {
await Actor.updateOne(
{ _id: req.params.id },
{ $pull: { movies: { title: req.body.movie }}},
{ multi: true }
)
res.status(200).json({ success: true, data: 'ok' })
} catch (error) {
res.status(400).json({ success: false, error: error })
}
}

Mongoose updateMany by id using Node

is it possible to update array of object by id? ex.:
This is my array:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 1,
"title": "first"
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 2,
"title": "second"
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 3,
"title": "last"
}
]
and I would like to change only the order of each by ID. I am using Node and I tried to do like that:
router.post("/edit-order", auth, async (req, res) => {
try {
const sections = await Section.updateMany(
req.body.map((item) => {
return { _id: item._id }, { $set: { order: item.order } };
})
);
res.json(sections);
} catch (e) {
res.status(500).json({ message: "Something went wrong in /edit-order" });
}
});
my request body is:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 2
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 3
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 4
}
]
but as a result, I got:
[
{
"_id": "5fdb614d686e671eb834a409",
"order": 4,
"title": "first"
},
{
"_id": "5fdb61c0686e671eb834a41e",
"order": 4,
"title": "second"
},
{
"_id": "5fdb61d6686e671eb834a424",
"order": 4,
"title": "last"
}
]
so, it change every order by the last value of request array. Any ideas how could I manage that. If you know any other solution feel free to share, all what I need is to change order only by id.
Well, since you have a different value of order for each item, you'll need to do a bulkWrite.
router.post('/edit-order', auth, async (req, res) => {
try {
const writeOperations = req.body.map((item) => {
return {
updateOne: {
filter: { _id: item._id },
update: { order: item.order }
}
};
});
await Section.bulkWrite(writeOperations);
res.json(req.body);
} catch (e) {
res.status(500).json({ message: 'Something went wrong in /edit-order' });
}
});
If you had a single value of order to all the items, you could've used updateMany along with $in.
router.post('/edit-order', auth, async (req, res) => {
try {
const sectionsIds = req.body.map((item) => {
return item._id;
});
const sections = await Section.updateMany(
{ _id: { $in: sectionsIds } },
{ order: 'A single value for all sections in body' }
);
res.json(sections);
} catch (e) {
res.status(500).json({ message: 'Something went wrong in /edit-order' });
}
});

how can I get value in populate() in mongoose?

I want to return one index's object of the array,
but when I query, It returns to me that all of the documents.
This is my Schema(userTb)
const userTbSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
userId: String,
gender: String
}
And this is my another Schema(product)
const productSchema = new Schema({
_id: mongoose.Schema.Types.ObjectId,
product: String,
userTbId: { type: mongoose.Schema.Types.ObjectId, ref: "userTb", required: true },
}
And They are in another js file.
This is the result of the query of my Schema(product) don't use Populate.
{
"_id": "5fc4c13f32ab3174acb01234",
"product": "watch",
"userTbId": "5fc4c13f32ab3174acb08540"
},
{
"_id": "5fc4c2d6b3a2a054d4dc1235",
"userId": "car",
"userTbId": "5fc4c2d6b3a2a054d4dc462c"
}
And This is the result of the query of my Schema(product) when I using Populate.
{
"_id": "5fc4c13f32ab3174acb01234",
"product": "watch",
"userTbId": {
"_id": "5fc4c13f32ab3174acb08540",
"userId": "go05111",
"gender": "male"
}
},
{
"_id": "5fc4c2d6b3a2a054d4dc1235",
"userId": "car",
"userTbId": {
"_id": "5fc4c2d6b3a2a054d4dc462c",
"userId": "Chips",
"gender": "female"
}
}
I want to get the only { "gender" : "male" } object in proudct, like...
{
"_id": "5fc4c13f32ab3174acb01234",
"product": "watch",
"userTbId": {
"_id": "5fc4c13f32ab3174acb08540",
"userId": "go05111",
"gender": "male"
}
}
so I query like this
router.get('/:gender', (req, res, next) => {
Product.find({
"userTbId.gender": req.params.gender
})
.populate({
path: 'userTbId',
match: {
userId: req.params.userId
}
})
.exec()
.then(docs => {
res.status(200).json({
docs
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});
but the result is nothing returned.
I think the userTbId is ObjectId, so even if populate() is used, the value does not appear when find() is used.
I tried a few different ways, but it didn't work that I want.
how can I fix it in mongoose?
would you please help me?
In mongoose, populate will execute on the result set from the find query.
In your Product schema userTbId is an object id and it will not have the gender property unless it gets populated. To achieve your goal only by using mongoose, you can write a query like below. First you need to find all the userTbIds for your gender and userId. Then query your Product schema for the returned userTbIds. Corrections and optimisations are welcome.
router.get('/:gender', (req, res, next) => {
userTbId.find({
"gender": req.params.gender,
"userId": req.params.userId
}).exec()
.then(docs => {
let ids = docs.map(doc => doc.id);
Product.find({
"userTbId": {$in:ids}
})
.populate({
path: 'userTbId'
})
.exec()
.then(docs => {
res.status(200).json({
docs
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});

Delete id within nested array

So far I can only manage to delete the first id (in this case the id with "12345").
Im trying to delete the row with id 2 within books-array
Libary Table:
{
"_id": {
"$oid": "12345"
},
"libaryName": "A random libary",
"Books": [
{
"_id": {
"$oid": "1"
}
"bookTitle": "Example",
"TotalPages": "500"
},
{
"_id": {
"$oid": "2"
}
"bookTitle": "Delete Me",
"TotalPages": "400"
}
]
}
My delete code:
router.delete('/:id', (req, res) => {
Libary.remove({ _id: req.params.id })
.then(() => {
//redirect
});
});
How can I reach and delete the book row where the id is 2?
You need to use $pull opertator
router.delete('/:id', (req, res) => {
Libary.update({ _id: req.params.id }, //This is the Id of library Document
{ $pull: { "Books": {"_id":2) } } }) // This will be the Id of book to be deleted
.then(() => {
//redirect
});
});
Hope it helps.
You need to use $pull:
Library.update(
{ },
{ $pull: { Books: { _id: 2 } } }
)

How to remove a specific field by given conidtion in mongodb?

I am not being able to remove the specific eventid from the UserSchema. I searched for this and got a method using unset but that is removing the whole user while the push function is not doing anything. Is there any other way to do this?
Current UserSchema
[
{
"_id": "56593f3657e27af8245735d7",
"username": "abc",
"name": "xyz",
"__v": 0,
"favouriteid": [
{
"eventid": "5659242639e43bfc2a0836b9",
"_id": "56593f6b57e27af8245735d8"
},
{
"eventid": "5659244039e43bfc2a0836ba",
"_id": "56593f8857e27af8245735d9"
}
]
}
]
What I need-
[
{
"_id": "56593f3657e27af8245735d7",
"username": "abc",
"name": "xyz",
"__v": 0,
"favouriteid": [
{
"eventid": "5659242639e43bfc2a0836b9",
"_id": "56593f6b57e27af8245735d8"
}
]
}
]
I will be passing eventid and userid
But when I am using this code, the user gets deleted itself rather than the required field.
api.post('/removefavourites', function (req, res) {
// _id: req.body.id;
User.findById({_id: req.body.userid},
{$unset:{favouriteid: {eventid: req.body.eventid}}},
{upsert: true},
function (err) {
if(err)
return err;
else
res.json({success: true});
});
});
You can use update method with pull operation as shown below:
api.post('/removefavourites', function (req, res) {
// _id: req.body.id;
User.update({_id: req.body.userid},
{$pull:{favouriteid: {eventid: req.body.eventid}}},
function (err) {
if(err)
return err;
else
res.json({success: true});
});
});
Hope this helps :)

Resources