Delete id within nested array - node.js

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 } } }
)

Related

MongoDb aggregation for daily number of views and downloads

const fetchSummary = expressAsyncHandler(async (req, res) => {
//GET DAILY SUMMARY
const dailySummary = await Post.aggregate([
{
$group: {
_id: { $dateToString: { format: "%Y-%m-%d", date: "$createdAt" } },
downloads: { $sum: "$downloadCount" },
totalViews: { $sum: "$numViews" },
},
},
{ $sort: { _id: -1 } },
]);
res.send({ dailySummary });
});
Can someone please help me out here, I'm trying to fetch sum total for daily views and downloads for a post
And here is my result
"dailySummary": [
{
"_id": "2023-01-07",
"downloads": 49,
"totalViews": 227
},
{
"_id": "2023-01-06",
"downloads": 41,
"totalViews": 605
},
{
"_id": "2023-01-05",
"downloads": 0,
"totalViews": 0
}
],
And this result is a wrong
number of views for today is not even up 40,and downloads 10
//============
// Fetch single Post
//============
const fetchPostCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
validateMongodbId(id);
try {
const post = await Post.findById(id).populate("user comments");
//Updating Number of views
await Post.findByIdAndUpdate(
id,
{
$inc: { numViews: 1 },
},
{ new: true }
);
res.json(post);
} catch (error) {
res.json(error);
}
});
This is how I'm fetching post details

mongoose divide two fields in put request

Can I update a field of a document with a division of two fields? Using Node and MongoDB, I'm trying to create a rating function, and I have to make a division, but nothing seems to work. I want the new value of rating to be, the current one divided by the number of votes.
router.put("/:id/:rating", async (req, res) => {
const movie_rating = parseInt(req.params.rating);
try {
const updatedMovie = await Movie.findByIdAndUpdate(
req.params.id,
{
$inc: { noVotes: 1 },
$inc: { rating: movie_rating },
$divide: { rating: [rating, noVotes] },
// rating: { $divide: [rating, noVotes] }
},
{ new: true }
);
res.status(200).json(updatedMovie);
} catch (err) {
res.status(500).json(err);
}
});
You need to change few things
Sample
db.collection.update({},
[
{
"$set": {
"key2": {
$add: [
"$key2",
1
]
},
key3: {
"$divide": [
{
$add: [
"$key2",
1
]
},
"$key"
]
},
}
}
],
{
"multi": true,
"upsert": false
})
You need aggregate update as you need divide
You cannot use the updated value in the same operation
You cannot combine $inc, $set in aggregate update
Alternatively, you can use $add instead $inc
you can reperform the operation for the divide operation than making another update call
This can be done with $set,
It will look like this:
router.put("/:id/:rating", async (req, res) => {
const movie_rating = parseInt(req.params.rating);
try {
const updatedMovie = await Movie.findByIdAndUpdate(
req.params.id,
[
{
$set: {
noVotes: { $sum: ["$noVotes", 1] },
rating: { $sum: ["$rating", movie_rating] },
averageRating: { $divide: ["$rating", "$noVotes"] },
},
},
],
{ new: true }
);
res.status(200).json(updatedMovie);
} catch (err) {
res.status(500).json(err);
}
});

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 one document in mongoose(mongoDB)?

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,
folders: [
{
folderTitle: String,
}
]
}
and this is the result of the query of my Schema(userTb).
{
"_id": "5fc4c13f32ab3174acb08540",
"userId": "go05111",
"folders": [
{
"_id": "5fb7b0473fddab615456b166",
"folderTitle": "first-go"
},
{
"_id": "5fb7b0473fddab615456b16b",
"folderTitle": "second-go"
}
]
}
I want to get the only { "folderTitle" : "first-go" } folder's object, like...
{
"_id": "5fb7b0473fddab615456b166",
"folderTitle": "first-go"
}
so I query like this
router.get('/folder/:folderId', (req, res, next) => {
UserTb.find({ folders : { "$elemMatch" : { _id : req.params.folderId} } })
.exec()
.then(docs => {
res.status(200).json({
docs
});
})
.catch(err => {
res.status(500).json({
error: err
});
});
});
but the result is nothing changed.
I tried a few different ways, but it didn't work out.
how can I fix it?
please help me...
Try this (live version):
UserTb.aggregate({
$match: {
"folders._id": req.params.folderId }
},
{
$project: {
folders: {
$filter: {
input: "$folders",
as: "f",
cond: {
$eq: [
"$$f.folderTitle",
"first-go"
]
}
}
},
_id: 0
}
})
It will retrieve folders:[{...}] this will be easy to tackle using JS, and quicker.
Mechanism
Match only documents containing _id:folderId
project only the inner document

How to pick a subdocument with its id?

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
});
});

Resources