meteor update field of subdocument given subdocument id (not position) [duplicate] - 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",
},
}
);

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....

Update field in exact element array in 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",
},
}
);