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....
Related
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+" } ]
}
)
I have a document like this:
{
"_id": ObjectId("5d779541bd4e75c58d598212")
"client": ObjectId("5d779558bd4e75c58d598213")
}
When I do $lookup like this:
{
from: 'client',
localField: 'client',
foreignField: 'id',
as: 'client',
}
I get:
{
"_id": ObjectId("5d779541bd4e75c58d598212")
"client":[
{
... client info wrapped in array
}
]
}
This forces me to add $unwind after the lookup stage.
This would work fine in this example because I know that it is a regular field (not array). But on other collections I have arrays of ObjectId's and I don't want to unwind them.
How should I tell mongo to unwind only if it's not an array?
Add $project stage with $arrayElemAt
{ $lookup ..... },
{ $project: { client: { $arrayElemAt: [ "$client" , 0 ]}} // Add other filed
The lookup always returns an array as it doesn't know if its a one-to-one or one-to-many mapping. But we can ensure that the lookup returns a single document and that document would hold all documents which were supposed to come as an array in the general lookup.
Following is the way:
db.collection.aggregate([
{
$lookup:{
"from":"client",
"let":{
"client":"$client"
},
"pipeline":[
{
$match:{
$expr:{
$eq:["$id","$$client"]
}
}
},
{
$group:{
"_id":null,
"data":{
$push:"$$ROOT"
}
}
},
{
$project:{
"_id":0
}
}
],
"as":"clientLookup"
}
},
{
$unwind:"$clientLookup"
}
]).pretty()
Query analysis: We are looking up into client collection and executing a pipeline inside that. The output of that pipeline would hold every matched document inside data field.
Data set:
Collection: collection
{
"client":1
}
{
"client":2
}
Collection: client
{
"id":1,
"name":"Tony"
}
{
"id":1,
"name":"Thor"
}
{
"id":1,
"name":"Natasha"
}
{
"id":2,
"name":"Banner"
}
Output:
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820c"),
"client" : 1,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d59820e"),
"id" : 1,
"name" : "Tony"
},
{
"_id" : ObjectId("5d779322bd4e75c58d59820f"),
"id" : 1,
"name" : "Thor"
},
{
"_id" : ObjectId("5d779322bd4e75c58d598210"),
"id" : 1,
"name" : "Natasha"
}
]
}
}
{
"_id" : ObjectId("5d7792c6bd4e75c58d59820d"),
"client" : 2,
"clientLookup" : {
"data" : [
{
"_id" : ObjectId("5d779322bd4e75c58d598211"),
"id" : 2,
"name" : "Banner"
}
]
}
}
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",
},
}
);
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",
},
}
);
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",
},
}
);