Remove element from nested array mongodb - node.js

i have the following document , it has two array's , one inside the other ,
attachment array and files array inside attachment array .
i want to delete an element inside files array using this element _id . but its not working with me , i tried this code , it return
{ n: 144, nModified: 0, ok: 1 }
Invoice.update({}, {
$pull: {
"attachment":
{
"files":
{
$elemMatch:
{ _id: ObjectId("5b7937014b2a961d082de9bf") }
}
}
}
}, { multi: true })
.then(result => {
console.log("delete", result);
});
this is how the document looks like

You can try below update query in 3.6 version.
Invoice.update(
{},
{"$pull":{"attachment.$[].files":{_id:ObjectId("5b7969ac8fb15f3e5c8e844e")}}},
{"multi": true}, function (err, result) {console.log(result);
});
Use db.adminCommand( { setFeatureCompatibilityVersion: 3.6 or 4.0 depending on your version } ) if your are upgrading from old version.

For Mongodb version prior to 3.6
There is only one nested level here so you can simply use $ positional operator.
Invoice.update(
{ "attachment.files._id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") },
{ "$pull": { "attachment.$.files": { "_id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") }}},
{ "multi": true }
)
For Mongodb version 3.6 and above
If you want to update multiple elements inside attachement array then you can use $[] the all positional operator.
const mongoose = require("mongoose")
Invoice.update(
{ "attachment.files._id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") },
{ "$pull": { "attachment.$[].files": { "_id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") }}},
{ "multi": true }
)
And If you want to update single element inside the attachment array then you can use $[<identifier>] that identifies the array elements that match the arrayFilters conditions.
Suppose you want to update only an element inside attachment having _id equal to ObjectId(5b7934f54b2a961d081de9ab)
Invoice.update(
{ "attachment.files._id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") },
{ "$pull": { "attachment.$[item].files": { "_id": mongoose.Types.ObjectId("5b7937014b2a961d082de9bf") } } },
{ "arrayFilters": [{ "item._id": mongoose.Types.ObjectId("5b7934f54b2a961d081de9ab") }], "multi": true }
)

Related

How to update nested documents in an array in mongodb document without using positional operator $?

I have an issue in which I am not able to use the positional operator to update subdocuments because I am using MongoDB version 3.2 which doesn't support the positional operator $, and I am not able to upgrade MongoDB version to more than 3.2 due to the 32-bit MongoDB support
I want to change the value of the field order in the subdocument to the boolean value false
[
{
"_id": 1,
"products": {
"books": [
{
"id": 1,
"ordered": true
},
{
"id": 2,
"ordered": false
}
]
}
}
]
and if there is a mongoose way to do it , I would be thankfull
Sadly not much you can do, if you know the index of the array you can use that:
db.collection.update({},
{
"$set": {
"products.books.0.ordered": false
}
})
If you don't you need to find the document first and then update it:
const doc = await db.collection.findOne({});
if (doc) {
const indexToUpdate = doc.products.items.map((item, index) => ({...item, index})).filter(v => v.item.ordered === true);
if (indexToUpdate.length) {
const setBody = {}
indexToUpdate.forEach((item) => {
const key = `products.books.${item.index}.ordered`
setBody[key] = false;
})
await db.collection.update({},
{
"$set": setBody
})
}
}

Update nested object in array MongoDB

I need to find and update documents with category that corresponding to the query. Array could contain mo than one corresponding id.
Query:
{
"ids": ["61f1cda47018c60012b3dd01", "61f1cdb87018c60012b3dd07"],
"userId": "61eab3e57018c60012b3db3f"
}
I got collection with documents like:
`{
"_id":{"$oid":"61f1cdd07018c60012b3dd09"},
"expenses":[
{"category":"61eafc104b88e154caa58616","price":"1111.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"2222.00"},
{"category":"61f1cda47018c60012b3dd01","price":"1241.00"},
{"category":"61f1cdb87018c60012b3dd07","price":"111.00"}
],
"userId":"61eab3e57018c60012b3db3f"
}`
my method:
async myMethod(ids: [string], userId: string) {
try {
const { ok } = await this.ExpensesModel.updateMany(
{"userId": userId, "expenses.category": { $in: ids }},
{$set: {"expenses.$.category": "newCategoryID"}}
);
return ok
} ........
I path array of ids ["61f1cda47018c60012b3dd01","61f1cdb87018c60012b3dd07","61f1cdb87018c60012b3dd07"] and userId, this code update only 1 category by document.
So can i made it with mongo build in methods? or i need to find matching document and update it it by my self and after that update or insert;
Update with arrayFilters
db.collection.update({
"expenses.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
},
{
$set: {
"expenses.$[elem].category": "61eab3e57018c60012b3db3f"
}
},
{
arrayFilters: [
{
"elem.category": {
$in: [
"61f1cda47018c60012b3dd01",
"61f1cdb87018c60012b3dd07"
]
}
}
]
})
mongoplayground

MongoDB updating array of objects does not work as expected

Got multiple documents in a db one of which looks like this:
{
"searchWord":[
"pizz",
"pizza"
],
"result":[
{
"idMeal":1,
"strMeal":"test1",
"strInstructions":"test1"
},
{
"idMeal":2,
"strMeal":"test2",
"strInstructions":"test2"
}
]
}
Tried to solve it like this:
eg:
db.meals.updateOne(
{
"searchWord": "pizz",
"result": { $elemMatch: { idMeal: "1" } }
},
{ $set: { 'result.$.strMeal' : "UPDATED" } }
)
This doesnt update the respective subdocument only the 2nd as if I wrote
{ $set: { 'result.1.strMeal' : "UPDATED" } }
(Which will result in the 2nd subdocument being updated)
This is the other idea (Same result)
db.meals.updateOne(
{ searchWord: "pizz", 'result.idMeal': 319012 },
{ $set: { "result.$.strMeal" : "fsdf" } }
)
What I dont seem to understand is its exactly the syntax that is provided by mongo yet it doesnt work
The "$" operator doesnt pick up which array of objects I wanna update
Try to use $[] in your $set for multiple positional element
db.collection.update({
"searchWord": "pizz"
},
{
$set: {
"result.$[r].strMeal": "UPDATED"
}
},
{
arrayFilters: [
{
"r.idMeal": 1
}
]
})
Here is the Mongo playground for your reference.

Mongoose findbyIdAndUpdate - how to update one field using sum from another array field

So this is how my document looks like
"donator": [
{
"_id": "5edbd7d182af1f5aceab62bb",
"donatorName": "Niki",
"donationValue": 5000000
},
{
"_id": "5edbd7d182af1f5aceab62bc",
"donatorName": "Brian",
"donationValue": 5000000
}
],
"currentValue" : 1000000
I get my currentValue from donationValue sum in donator array :
donator.reduce((a, { donationValue }) => a + donationValue,0);
and I want to update the document by adding new object in donator array, and automatically updates currentValue field when the data updated.
I tried using aggregate
MyCollection.findByIdAndUpdate(id, [
{
$set: req.body,
$set: { currentValue: { $sum: { $sum: donator.donationValue } } },
},
]);
It's a good practice to sanitise your input and not directly use req.body.
so let's say
const donator = sanitizeDonator(req.body)
Then you can add donator and update currentValue as follows.
Note that _id on donator won't be auto generated by the update query, so it has to be present in the donator object.
MyCollection.findByIdAndUpdate(id, [
{
$set: {
donator: {
$concatArrays: ["$donator", [donator]] // adding donator to the last element
}
}
}, {
$set: {
currentValue: {
$reduce: {
initialValue: 0,
input: "$donator",
in: {
$add: ["$$this.donationValue", "$$value"]
}
}
}
}
}
]);
Relevant APIs
$concatArrays,
$reduce

How to update a array value in Mongoose

I want to update a array value but i am not sure about the proper method to do it ,so for i tried following method but didnt worked for me.
My model,
The children field in my model
childrens: {
type: Array,
default: ''
}
My query,
Employeehierarchy.update({ _id: employeeparent._id} ,{ $set: {"$push": { "childrens": employee._id }} })
.exec(function (err, managerparent) {});
Can anyone please provide me help.Thanks.
You can't use both $set and $push in the same update expression as nested operators.
The correct syntax for using the update operators follows:
{
<operator1>: { <field1>: <value1>, ... },
<operator2>: { <field2>: <value2>, ... },
...
}
where <operator1>, <operator2> can be from any of the update operators list specified here.
For adding a new element to the array, a single $push operator will suffice e.g. you can use the findByIdAndUpdate update method to return the modified document as
Employeehierarchy.findByIdAndUpdate(employeeparent._id,
{ "$push": { "childrens": employee._id } },
{ "new": true, "upsert": true },
function (err, managerparent) {
if (err) throw err;
console.log(managerparent);
}
);
Using your original update() method, the syntax is
Employeehierarchy.update(
{ "_id": employeeparent._id},
{ "$push": { "childrens": employee._id } },
function (err, raw) {
if (err) return handleError(err);
console.log('The raw response from Mongo was ', raw);
}
);
in which the callback function receives the arguments (err, raw) where
err is the error if any occurred
raw is the full response from Mongo
Since you want to check the modified document, I'd suggest you use the findByIdAndUpdate function since the update() method won't give you the modified document, just the full write result from mongo.
If you want to update a field in the document and add an element to an array at the same time then you can do
Employeehierarchy.findByIdAndUpdate(employeeparent._id,
{
"$set": { "name": "foo" },
"$push": { "childrens": employee._id }
}
{ "new": true, "upsert": true },
function (err, managerparent) {
if (err) throw err;
console.log(managerparent);
}
);
The above will update the name field to "foo" and add the employee id to the childrens array.
can follow this
if childrens contains string values then model can be like:
childrens: [{
type : String
}]
if childrens contains ObjectId values of another collection _id and want populate then model can be like:
childrens: [{
type : mongoose.Schema.Types.ObjectId,
ref: 'refModelName'
}]
no need to use $set just use $push to insert value in childrens array. so query can be like:
Employeehierarchy.update(
{ _id: employeeparent._id},
{"$push": { "childrens": employee._id } }
).exec(function (err, managerparent) {
//
});
This will help I guess
Employeehierarchy.findOneAndUpdate(
{ _id:employeeparent._id },
{ $set: { "childrens": employee._id }}
)

Resources