Mongodb Updating Fields in Nested Array

Update nested array objects based on a property in MongoDB

You need to use $ positional operator to update an array element and with multi: true option you can update multiple document with the same match

db.collection.update(
{ 'items': { '$elemMatch': { 'itemName': 'Name 1' }}},
{ '$set': { 'items.$.itemName': 'New Name' }},
{ 'multi': true }
)

and with the mongodb 3.6 arrayFilters

db.collection.update(
{ 'items': { '$elemMatch': { 'itemName': 'Name 1' }}},
{ '$set': { 'items.$[item].itemName': 'New Name' }},
{ 'arrayFilter': [{ 'item.itemName': 'Name 1' }], 'multi': true }
)

Update nested array field for multiple docs at once

With arrayFilters and filtered $[<identifier>] operator.

db.collection.update({},
{
$set: {
"History.$[].dev.$[dev].floor": ""
}
},
{
arrayFilters: [
{
"dev.floor": "n/a"
}
],
multi: true
})

Sample Mongo Playground

How can I update a multi level nested array in MongoDB?

Since Mongo 3.6, you can update multi-nested arrays by combining the following operators:

  • $set (to update a specific field)
  • $[] (to match any item in an array)
  • $[<identifier>] (to match specific items in an array)

Example

Here's how you can update a specific proyectos document that has a reuniones array that has a participantes array that has an object with the field nomina equal to 2:

// update a specific proyectos document
// that has a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2
db.proyectos.update({
_id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
$set: {
"reuniones.$[].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"j.nomina": 2
}
]
})

If you wanted to limit your query to a specific reunion, you can do:

db.proyectos.update({
_id: ObjectId("5bfa09f0a0441f38d45dcc9c"),
}, {
$set: {
"reuniones.$[i].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"i._id": ObjectId("5bfa09f0a0441f38d45dcc99")
},
{
"j.nomina": 2
}
]
})

To update all proyectos satisfying the above condition, just omit the _id query:

// update all proyectos
// that have a field "reuniones" which is an array
// in which each item is an object with a field "participantes" that is an array
// in which each item is an object that has a field "nomina" equal to 2
db.proyectos.update({}, {
$set: {
"reuniones.$[].participantes.$[j].firma": <your update>
},
}, {
arrayFilters: [
{
"j.nomina": 2
}
]
})

Updating a nested Array in using UpdateOne()

As there's two nested arrays in your document, you can't set the field with classic positional operator '$'.

Instead, you should use the arrayFilters option like this:

db.collection.update({
"_id": ObjectId("6032a5ad80443334a35f2232")
},
{
$set: {
"List.$[list].customData.$[customData].systemUpdate_DT": "updatedDTTM"
}
},
{
"multi": false,
"upsert": false,
arrayFilters: [
{
"list._id": {
"$eq": ObjectId("6032a5af80443334a35f2234")
}
},
{
"customData._id": {
"$eq": ObjectId("6032a5bc80443334a35f223c")
}
}
]
})

try it online: mongoplayground.net/p/fb_86rNUKvt

MongoDB - Update all entries in nested array only if they exist

I don't think its possible with arrayFilted for first level and second level update, but yes its possible only for third level update,

The possible way is you can use update with aggregation pipeline starting from MongoDB 4.2,

I am just suggesting a method, you can simplify more on this and reduce query as per your understanding!

Use $map to iterate the loop of children array and check condition using $cond, and merge objects using $mergeObjects,

let id = req.body._id;
let oldname = req.body.name;
let route = req.body.route;
let newname = req.body.newName;

let segments = route.split('/');

LEVEL 1 UPDATE: Playground

// LEVEL 1: Example Values in variables
// let oldname = "l1";
// let route = "l1";
// let newname = "l4";
if(segments.length === 1) {
let result = await NavItems.updateOne(
{ _id: id },
[{
$set: {
name: newname,
route: newname,
children: {
$map: {
input: "$children",
as: "a2",
in: {
$mergeObjects: [
"$$a2",
{
route: { $concat: [newname, "/", "$$a2.name"] },
children: {
$map: {
input: "$$a2.children",
as: "a3",
in: {
$mergeObjects: [
"$$a3",
{ route: { $concat: [newname, "/", "$$a2.name", "/", "$$a3.name"] } }
]
}
}
}
}
]
}
}
}
}
}]
);
}

LEVEL 2 UPDATE: Playground

// LEVEL 2: Example Values in variables
// let oldname = "l2a";
// let route = "l1/l2a";
// let newname = "l2g";
else if (segments.length === 2) {
let result = await NavItems.updateOne(
{ _id: id },
[{
$set: {
children: {
$map: {
input: "$children",
as: "a2",
in: {
$mergeObjects: [
"$$a2",
{
$cond: [
{ $eq: ["$$a2.name", oldname] },
{
name: newname,
route: { $concat: ["$name", "/", newname] },
children: {
$map: {
input: "$$a2.children",
as: "a3",
in: {
$mergeObjects: [
"$$a3",
{ route: { $concat: ["$name", "/", newname, "/", "$$a3.name"] } }
]
}
}
}
},
{}
]
}
]
}
}
}
}
}]
);
}

LEVEL 3 UPDATE: Playground

// LEVEL 3 Example Values in variables
// let oldname = "l3a";
// let route = "l1/l2a/l3a";
// let newname = "l3g";
else if (segments.length === 3) {
let result = await NavItems.updateOne(
{ _id: id },
[{
$set: {
children: {
$map: {
input: "$children",
as: "a2",
in: {
$mergeObjects: [
"$$a2",
{
$cond: [
{ $eq: ["$$a2.name", segments[1]] },
{
children: {
$map: {
input: "$$a2.children",
as: "a3",
in: {
$mergeObjects: [
"$$a3",
{
$cond: [
{ $eq: ["$$a3.name", oldname] },
{
name: newname,
route: { $concat: ["$name", "/", "$$a2.name", "/", newname] }
},
{}
]
}
]
}
}
}
},
{}
]
}
]
}
}
}
}
}]
);
}


Why separate query for each level?

You could do single query but it will update all level's data whenever you just need to update single level data or particular level's data, I know this is lengthy code and queries but i can say this is optimized version for query operation.

How to update a value in a array of nested object in Mongoose(Momgodb)?

You can update a value in an array of nested objects in Mongoose

`db.users.update({"pm.checkList.ch_id" : "621eff4e0ed5c751adaa42fb"},{ $set:{
"pm.checkList.$.val" : "nop",
"pm.checkList.$.remarks" : "bed",
}})`

Mongodb update pipeline update a field of a element inside a nested array

I don't think any other straightway to update the specific index position element using aggregation pipeline,

  • $range to generate array from 0 to length of materials.m1.inventory array
  • $map to iterate loop of above range array
  • $cond to check current element is 0 then go to update part otherwise return element from materials.m1.inventory by input index
  • $arrayElemAt to get specific element from materials.m1.inventory
  • $mergeObjects to merge current object with amount updated property
await products.findOneAndUpdate(filters, [
{
$set: {
"materials.m1.inventory": {
$map: {
input: {
$range: [0, { $size: "$materials.m1.inventory" }]
},
in: {
$cond: [
{ $eq: ["$$this", 0] }, // 0 position
{
$mergeObjects: [
{ $arrayElemAt: ["$materials.m1.inventory", "$$this"] },
{ amount: 100 } // input amount
]
},
{ $arrayElemAt: ["$materials.m1.inventory", "$$this"] }
]
}
}
}
}
}
]);

Playground



Related Topics



Leave a reply



Submit