Update field in exact element array in MongoDB - mongodb

I have a document structured like this:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "", ""] },
{ nickname : "test2", items : ["", "", ""] },
]
}
Can I $set the second element of the items array of the embedded object in array heros with nickname "test" ?
Result:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "new_value", ""] }, // modified here
{ nickname : "test2", items : ["", "", ""] },
]
}

You need to make use of 2 concepts: mongodb's positional operator and simply using the numeric index for the entry you want to update.
The positional operator allows you to use a condition like this:
{"heroes.nickname": "test"}
and then reference the found array entry like so:
{"heroes.$ // <- the dollar represents the first matching array key index
As you want to update the 2nd array entry in "items", and array keys are 0 indexed - that's the key 1.
So:
> db.denis.insert({_id:"43434", heroes : [{ nickname : "test", items : ["", "", ""] }, { nickname : "test2", items : ["", "", ""] }]});
> db.denis.update(
{"heroes.nickname": "test"},
{$set: {
"heroes.$.items.1": "new_value"
}}
)
> db.denis.find()
{
"_id" : "43434",
"heroes" : [
{"nickname" : "test", "items" : ["", "new_value", "" ]},
{"nickname" : "test2", "items" : ["", "", "" ]}
]
}

Try update document in array using positional $,
The positional $ operator facilitates updates to arrays that contain embedded documents. Use the positional $ operator to access the fields in the embedded documents with the dot notation on the $ operator.
db.collection.update(
{ "heroes.nickname": "test" },
{ $set: { "heroes.$.items.1": "new_value" } },
{ multi: true }
);
Playground

This solution works well. Just want to add one point.
Here is the structure. I need to find OrderItemId is 'yyy' and update.
If the query field in condition is an array, like below "OrderItems.OrderItemId" is array. You can not use "OrderItems.OrderItemId[0]" as operation in the query. Instead, you need to use "OrderItems.OrderItemId" to compare. Otherwise, it can not match one.
{
_id: 'orderid',
OrderItems: [
{
OrderItemId: ['xxxx'],
... },
{
OrderItemId: ['yyyy'],
...},
]
}
result = await collection.updateOne(
{ _id: orderId, "OrderItems.OrderItemId": [orderItemId] },
{ $set: { "OrderItems.$.imgUrl": imgUrl[0], "OrderItems.$.category": category } },
{ upsert: false },
)
console.log(' (result.modifiedCount) ', result.modifiedCount)
console.log(' (result.matchedCount) ', result.matchedCount)

Try update with positional $ and $position,
db.collection.update(
{ heroes:{ $elemMatch:{ "nickname" : "test"} } },
{
$push: {
'heroes.$.items': {
$each: ["new_value" ],
$position: 1
}
}
}
)

go further! Use string template for paste your variable indexes in the way
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
[`heroes.${heroesIndex}.items.${itemIndex}`]: "new_value",
},
}
);
or
without template
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
'heroes.0.items.1': "new_value",
},
}
);

Related

I want to know how to write an update script for Mongo DB

I want to know how to write the mongodb script for updating the field in my db
my collection is something like this
{
_id: 1,
name: xyz,
answer: [
{ type: 'C',
from: 0
},
{ type: 'M',
from: 0
},
{ type: 'P',
from: 0
}
........ so on
]
}
.
.
.
and other objects
I want to add a field called "test" in each object of answer array whose "type" value is not 'C'
I am new to this. Can someone help me how should i do this.
Are you looking for this:
db.col.updateOne(
{ name: "xyz" },
{ "$set": { 'answer.$[i].test': null } },
{ arrayFilters: [{ "i.type": { $ne: "C" } }] }
)
Result:
{
"name" : "xyz",
"answer" : [
{
"type" : "C",
"from" : 0.0
},
{
"type" : "M",
"from" : 0.0,
"test" : null
},
{
"type" : "P",
"from" : 0.0,
"test" : null
}
]
}
If you like to update all documents in your collection use updateMany() and skip filter { name: "xyz" }
Of course you can run the update manually like this:
db.col.find().forEach(function (doc) {
doc.answer.forEach(function (i) {
if (i.type != "C")
i.test = null;
})
db.col.updateOne(
{ _id: doc._id },
{ $set: doc }
)
})
but you have to admit, arrayFilters is shorter and more convenient.

How to update particular value inside array - Mongodb

I have a mongodb collection Users that looks like this:
{
"_id" : ObjectId("5dba8987b4a39c13bc104a23"),
"contact" : {
"firstName" : "Mark",
"lastName" : "Doe",
"parentsBloodType" : [
{
"type" : "AB+",
},
{
"type" : "A+",
},
],
},
"createdAt" : ISODate("2019-10-31T07:13:11.278Z"),
"updatedAt" : ISODate("2019-11-26T09:59:41.611Z")
}
I need to run a raw query to update from AB+ to O-. I would also like to check if they match before updating.
I tried this but it added an extra field to the User:
db.getCollection('users').update(
{"_id": ObjectId("5dba8987b4a39c13bc104a23")},
{"$set" : { 'parentsBloodType.' + '0' + '. type' : "O-"}}
)
This one would do the update:
db.users.update(
{ "_id": ObjectId("5dba8987b4a39c13bc104a23") },
{ "$set": { 'contact.parentsBloodType.0.type' : "O-"} }
)
You an check match with this:
db.users.update(
{
"_id": ObjectId("5dba8987b4a39c13bc104a23"),
"contact.parentsBloodType.type": "AB+"
},
{ "$set": { 'contact.parentsBloodType.0.type': "AB+" } }
)
This updates the document only if type AB+ exist (at any parent).
Or if you like to check whether the first type is AB+ then use
db.users.update(
{
"_id": ObjectId("5dba8987b4a39c13bc104a23"),
"contact.parentsBloodType.0.type": "AB+"
},
{ "$set": { 'contact.parentsBloodType.0.type': "AB+" } }
)
However, I assume you are actually looking for this:
db.users.update(
{ "_id": ObjectId("5dba8987b4a39c13bc104a23") },
{ "$set": { 'contact.parentsBloodType.$[p].type': "0-" } },
{ arrayFilters: [{ "p.type": "AB+" }] }
)
Which will update any AB+ to 0- no matter on which position it appears in the array.
You could use the positional $ operator to update the first element that matches the query document:
db.getCollection('users').update(
{ "_id": ObjectId("5dba8987b4a39c13bc104a23"), "parentsBloodType.type": "AB+" },
{ "$set" : { 'parentsBloodType.$.type' : "O-" } }
)
note that:
the positional $ operator acts as a placeholder for the first element that matches the query document, and
the array field must appear as part of the query document.
Or use the filtered positional operator $[] if you want to update all elements that match an array filter condition or conditions:
db.students.update(
{ "_id": ObjectId("5dba8987b4a39c13bc104a23") },
{ $set: { "parentsBloodType.$[element].type" : "O-" } },
{
arrayFilters: [ { "element.type": "AB+" } ]
}
)

Update Matched Object In Array [duplicate]

I have a document structured like this:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "", ""] },
{ nickname : "test2", items : ["", "", ""] },
]
}
Can I $set the second element of the items array of the embedded object in array heros with nickname "test" ?
Result:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "new_value", ""] }, // modified here
{ nickname : "test2", items : ["", "", ""] },
]
}
You need to make use of 2 concepts: mongodb's positional operator and simply using the numeric index for the entry you want to update.
The positional operator allows you to use a condition like this:
{"heroes.nickname": "test"}
and then reference the found array entry like so:
{"heroes.$ // <- the dollar represents the first matching array key index
As you want to update the 2nd array entry in "items", and array keys are 0 indexed - that's the key 1.
So:
> db.denis.insert({_id:"43434", heroes : [{ nickname : "test", items : ["", "", ""] }, { nickname : "test2", items : ["", "", ""] }]});
> db.denis.update(
{"heroes.nickname": "test"},
{$set: {
"heroes.$.items.1": "new_value"
}}
)
> db.denis.find()
{
"_id" : "43434",
"heroes" : [
{"nickname" : "test", "items" : ["", "new_value", "" ]},
{"nickname" : "test2", "items" : ["", "", "" ]}
]
}
Try update document in array using positional $,
The positional $ operator facilitates updates to arrays that contain embedded documents. Use the positional $ operator to access the fields in the embedded documents with the dot notation on the $ operator.
db.collection.update(
{ "heroes.nickname": "test" },
{ $set: { "heroes.$.items.1": "new_value" } },
{ multi: true }
);
Playground
This solution works well. Just want to add one point.
Here is the structure. I need to find OrderItemId is 'yyy' and update.
If the query field in condition is an array, like below "OrderItems.OrderItemId" is array. You can not use "OrderItems.OrderItemId[0]" as operation in the query. Instead, you need to use "OrderItems.OrderItemId" to compare. Otherwise, it can not match one.
{
_id: 'orderid',
OrderItems: [
{
OrderItemId: ['xxxx'],
... },
{
OrderItemId: ['yyyy'],
...},
]
}
result = await collection.updateOne(
{ _id: orderId, "OrderItems.OrderItemId": [orderItemId] },
{ $set: { "OrderItems.$.imgUrl": imgUrl[0], "OrderItems.$.category": category } },
{ upsert: false },
)
console.log(' (result.modifiedCount) ', result.modifiedCount)
console.log(' (result.matchedCount) ', result.matchedCount)
Try update with positional $ and $position,
db.collection.update(
{ heroes:{ $elemMatch:{ "nickname" : "test"} } },
{
$push: {
'heroes.$.items': {
$each: ["new_value" ],
$position: 1
}
}
}
)
go further! Use string template for paste your variable indexes in the way
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
[`heroes.${heroesIndex}.items.${itemIndex}`]: "new_value",
},
}
);
or
without template
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
'heroes.0.items.1': "new_value",
},
}
);

meteor update field of subdocument given subdocument id (not position) [duplicate]

I have a document structured like this:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "", ""] },
{ nickname : "test2", items : ["", "", ""] },
]
}
Can I $set the second element of the items array of the embedded object in array heros with nickname "test" ?
Result:
{
_id:"43434",
heroes : [
{ nickname : "test", items : ["", "new_value", ""] }, // modified here
{ nickname : "test2", items : ["", "", ""] },
]
}
You need to make use of 2 concepts: mongodb's positional operator and simply using the numeric index for the entry you want to update.
The positional operator allows you to use a condition like this:
{"heroes.nickname": "test"}
and then reference the found array entry like so:
{"heroes.$ // <- the dollar represents the first matching array key index
As you want to update the 2nd array entry in "items", and array keys are 0 indexed - that's the key 1.
So:
> db.denis.insert({_id:"43434", heroes : [{ nickname : "test", items : ["", "", ""] }, { nickname : "test2", items : ["", "", ""] }]});
> db.denis.update(
{"heroes.nickname": "test"},
{$set: {
"heroes.$.items.1": "new_value"
}}
)
> db.denis.find()
{
"_id" : "43434",
"heroes" : [
{"nickname" : "test", "items" : ["", "new_value", "" ]},
{"nickname" : "test2", "items" : ["", "", "" ]}
]
}
Try update document in array using positional $,
The positional $ operator facilitates updates to arrays that contain embedded documents. Use the positional $ operator to access the fields in the embedded documents with the dot notation on the $ operator.
db.collection.update(
{ "heroes.nickname": "test" },
{ $set: { "heroes.$.items.1": "new_value" } },
{ multi: true }
);
Playground
This solution works well. Just want to add one point.
Here is the structure. I need to find OrderItemId is 'yyy' and update.
If the query field in condition is an array, like below "OrderItems.OrderItemId" is array. You can not use "OrderItems.OrderItemId[0]" as operation in the query. Instead, you need to use "OrderItems.OrderItemId" to compare. Otherwise, it can not match one.
{
_id: 'orderid',
OrderItems: [
{
OrderItemId: ['xxxx'],
... },
{
OrderItemId: ['yyyy'],
...},
]
}
result = await collection.updateOne(
{ _id: orderId, "OrderItems.OrderItemId": [orderItemId] },
{ $set: { "OrderItems.$.imgUrl": imgUrl[0], "OrderItems.$.category": category } },
{ upsert: false },
)
console.log(' (result.modifiedCount) ', result.modifiedCount)
console.log(' (result.matchedCount) ', result.matchedCount)
Try update with positional $ and $position,
db.collection.update(
{ heroes:{ $elemMatch:{ "nickname" : "test"} } },
{
$push: {
'heroes.$.items': {
$each: ["new_value" ],
$position: 1
}
}
}
)
go further! Use string template for paste your variable indexes in the way
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
[`heroes.${heroesIndex}.items.${itemIndex}`]: "new_value",
},
}
);
or
without template
yourModel.findOneAndUpdate(
{ _id: "43434" },
{
$set: {
'heroes.0.items.1': "new_value",
},
}
);

How to add a sub document to sub document array in MongoDB

I have a collection in mogodb like this:
{
"_id" : ObjectId("5393006538efaae30ec2d458"),
"userName" : "shiva",
"userUnderApiKey" : 123456,
"groups" : [
{
"groupName" : "Default",
"groupMembers" : [ ]
}
]
}
I want to add a new group in the groups array as sub document, like the below
{
"_id" : ObjectId("5393006538efaae30ec2d458"),
"userName" : "shiva",
"userUnderApiKey" : 123456,
"groups" : [
{
"groupName" : "Default",
"groupMembers" : [ ]
},
{
"groupName" : "Family",
"groupMembers" : [ ]
}
]
}
How to insert new sub document in the array of sub documents.Any help would be appriciated
To add a new member to the array you just use $push as you normally would:
db.collection.update(
{ "_id": ObjectId("5393006538efaae30ec2d458") },
{
"$push": {
"groups": {
"groupName" : "Family",
"groupMembers" : [ ]
}
}
}
)
If you then wanted to add members to the array that member contains then you need to match the element you want to add to:
db.collection.update(
{
"_id": ObjectId("5393006538efaae30ec2d458"),
"groups.groupName" : "Family",
},
{
"$push": {
"groups.$.groupMembers" : "bill"
}
}
)
I think you would be interested in $push
The $push operator appends a specified value to an array.
and $addToSet
The $addToSet operator adds a value to an array only if the value is not already in the array. If the value is in the array, $addToSet does not modify the array.
you can find examples in the documents above. It would be something like:
db.collection.update({
_id: ObjectId("5393006538efaae30ec2d458")
}, {
$push: {
groups: {
"groupName": "Family",
"groupMembers": []
}
}
});
SampleModel:
{
"Name":String,
"brandid": {
type: Schema.ObjectId,
ref: 'BrandList.BrandItems',
}
}
BrandModel:
{
"BrandName" : String,
"BrandItems": [{
"KG": Number,
"_id" : {type: Schema.ObjectId}
}]
}
How to refered subdocument array Object id to another model..and also how to use populate for this "brandid"..
Pls give me some solutin to solve this problem....