How to remove an object from array of objects in mongoose? - node.js

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

Related

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 to update and delete item from array in mongoose?

I have a board object and I want to edit it from express and mongoose, this is my object:
"boardMembers": [
"5f636a5c0d6fa84be48cc19d",
],
"boardLists": [
{
"cards": [
{
"_id": "5f7c9b77eb751310a41319ab",
"text": "card one"
},
{
"_id": "5f7c9bb524dd8d42d469bba3",
"text": "card two"
}
],
"_id": "5f7c9b6b02c19f21a493cb7d",
"title": "list one",
"__v": 0
}
],
"_id": "5f63877177beba2e3c15d159",
"boardName": "board1",
"boardPassword": "123456",
"boardCreator": "5f636a5c0d6fa84be48cc19d",
"g_createdAt": "2020-09-17T15:57:37.616Z",
"__v": 46
}
Now this is my code, I tried to do it with $pull, but nothing happend when I check it on Postman
router.put("/delete-task/:list/:task", auth, boardAuth, async (req, res) => {
const listId = req.params.list;
const task = req.params.task;
const board = await Board.findOne({ _id: req.board._id });
if (!board) return res.status(404).send("no such board");
Board.findOneAndUpdate(
{ _id: req.board._id },
{ $pull: { "boardLists.$[outer].cards": { _id: task } } },
{
arrayFilters: [{ "outer._id": listId }],
}
);
await board.save();
res.send(board);
});
what I am missing here?
Hope this will work in your case, you just need to convert your ids into mongo objectId. So your code will look something like this:
import mongoose from "mongoose";
const task = mongoose.Types.ObjectId(req.params.task);
const listId = mongoose.Types.ObjectId(req.params.list);
board = await Board.findOneAndUpdate(
{ _id: req.board._id},
{ $pull: {
"boardLists.$[outer].cards": { _id: task }
}
},
{
arrayFilters: [{ "outer._id": listId }],
returnNewDocument: true
}
);
res.send(board);

Finding and Updating record - Mongoose

I am building an API to store friends names for a game, I have built the API to receive the post request as so :
exports.addFriends = async (req, res) => {
try {
console.log('hit');
console.log(req.body.friendNames);
const addUser = await User.updateOne(
{ uniqueid: req.body.uniqueid },
{ $push: { friendNames: [req.body.friendNames] } }
);
res.json({
addUser
});
} catch (error) {
console.log(error);
}
};
ad the post request as
const friends = await axios.post('/api/v1/users/add/friends', {
uniqueId: this.uniqueid,
friendNames: [
{
userName: 'test',
region: 'euw'
}
]
});
My API is being hit as a see the logs, but no record is made. My User Schema is as so
const userSchema = new mongoose.Schema({
uniqueid: {
type: String,
required: true,
trim: true
},
summonerName: {
type: String
},
friendNames: [
{
userName: String,
region: String
}
]
});
I get no error and the request seems to go through, but no records are added. Any ideas?
$push is used to add one element to the array. But using the $each array update operator, we can push an array of items.
Also, I used findOneAndUpdate with new:true option to retrieve the updated document, because updateOne doesn't return the updated document.
exports.addFriends = async (req, res) => {
try {
console.log(req.body.friendNames);
const addUser = await User.findOneAndUpdate(
{ uniqueid: req.body.uniqueid },
{ $push: { friendNames: { $each: req.body.friendNames } } },
{ new: true }
);
res.json({ addUser });
} catch (error) {
console.log(error);
res.status(500).send("Something went wrong");
}
}
Let's say we have this existing document:
{
"_id": "5e31c749f26d5f242c69f3aa",
"uniqueid": "uniqueid1",
"summonerName": "John",
"friendNames": [
{
"_id": "5e31c749f26d5f242c69f3ab",
"userName": "Max",
"region": "Germany"
}
],
"__v": 0
}
Let's send a request to the controller with this request body:
{
"uniqueid": "uniqueid1",
"friendNames": [
{
"userName": "Andrew",
"region": "England"
},
{
"userName": "Smith",
"region": "USA"
}
]
}
The response will be like this:
{
"addUser": {
"_id": "5e31c749f26d5f242c69f3aa",
"uniqueid": "uniqueid1",
"summonerName": "John",
"friendNames": [
{
"_id": "5e31c749f26d5f242c69f3ab",
"userName": "Max",
"region": "Germany"
},
{
"_id": "5e31c763f26d5f242c69f3ad",
"userName": "Andrew",
"region": "England"
},
{
"_id": "5e31c763f26d5f242c69f3ac",
"userName": "Smith",
"region": "USA"
}
],
"__v": 0
}
}

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

Create and update field Mongoose NodeJs

{
"_id": {
"$oid": "5a4e5b1d09fb590058bfdf86"
},
"name": "ProjectStore",
"imageURL": "none",
"longitude": 0,
"latitude": 0,
"rating": 5,
"leads": [
{
"customerId": "5a0c57db65a4931768716566",
"customerName": "testuser",
"interested": "testuser",
"_id": {
"$oid": "5a4e5b5409fb590058bfdf88"
}
}
],
"items": [
{
"name": "chat",
"categoryID": "5a0c2d292235680012bd12c9",
"semiCatID": "5a0c2d5f2235680012bd12cb",
"_id": {
"$oid": "5a4e5b3009fb590058bfdf87"
}
}
],
"__v": 2
}
I added my DB log, I try to write query that will let me update/push information to "LeadStatus".
This varible should be inside each object in the "leads" array.
I have the keys for the main id "5a4e5b1d09fb590058bfdf86"
I have the second key for the specific lead "5a4e5b5409fb590058bfdf88"
I just dont know how to write the query, for now i got this.... and got error.
Store.update(
{ _id: req.body.store._id, 'leads._id': 'req.body.lead._id', },
{ $set: { 'leads.$.LeadStatus': 'open' }, },
(err, result) => {
if (err) {
res.status(500)
.json({ error: 'Unable to update leads.', });
} else {
res.status(200)
.json(result);
}
}
);
Please Help,
Thanks.
I'm assuming you want the updated doc returned (you can choose to not do so as well, switch option new to false). You have to assign an object the value that you're updating and provide all the fields within the subfield you're updating, otherwise it will remove everything else. That's why you have to do a findOne first:
return Store.findOne({ '_id': "5a4e5b1d09fb590058bfdf86" })
.then((store) => {
if (!store) { // patient was not found for some reason
throw new Error(`Store id was not found`);
}
const options = {
new: true,
};
const updatedStore = Object.assign({}, store.toObject(), {
leads: [
{
"leadStatus": "open",
"customerId": "5a0c57db65a4931768716566",
"customerName": "testuser",
"interested": "testuser",
"_id": {
"$oid": "5a4e5b5409fb590058bfdf88"
}
}
],
});
return Store.findOneAndUpdate(
{ '_id': req.body.store._id },
{ $set: updatedStore },
options);
});
In case you're curious, you can build pre/virtual hooks off of findOneAndUpdate (no documentation for this), you won't lose anything from not using update.

Resources