add new item value into an embedded document in mongoDB - mongodb

I have a document :
{
"_id" : ObjectId("550c00f81bcc15211016699b"),
"name" : "book3",
"author" : "mno",
"publisher" : "pub",
"testa" : [
{
"item1" : "item1",
"item2" : "item2"
}
]
}
All I want to do is add another item in testa like:
{
"_id" : ObjectId("550c00f81bcc15211016699b"),
"name" : "book3",
"author" : "mno",
"publisher" : "pub",
"testa" : [
{
"item1" : "item1",
"item2" : "item2",
"item3 : "item3"
}
]
}
I tried using
db.books.update(
{ "author":"mno" },
{ $addToSet: { testa : {"item3":"item3"} } }
)
this gives
{
"_id" : ObjectId("550c05261bcc15211016699c"),
"name" : "book3",
"author" : "mno",
"publisher" : "pub",
"testa" : [
{
"item1" : "item1",
"item2" : "item2"
},
{
"item3" : "item3"
}
]
}
and i tried
db.books.update(
{ "author":"mno" , "testa.item1" : "item1"},
{ $set : {"testa.0" : {"item3":"item3"}}},
{upsert : true / false}
)
this gave
{
"_id" : ObjectId("550c05fa1bcc15211016699d"),
"name" : "book3",
"author" : "mno",
"publisher" : "pub",
"testa" : [
{
"item3" : "item3"
}
]
}
Am I doing something wrong, I checked everywhere
Insert an embedded document to a new field in mongodb document
and
Update or replace an embedded document in MongoDB collection
I tried wierd things... but.... Please help me get the query right
I also tried these using the C# driver
like
WriteConcernResult res = booksColl.Update(query, Update.Set("testa.$.item1", "itemedited"),UpdateFlags.Upsert);

The following statement should work
db.books.update(
{ "author":"mno" },
{ $set: { "testa.0.item3" : "item3"} }
)
You can use the dot notation to specify items in the array and then you can just set the new item3 field to what ever value you wish. You nearly had it right in your examples above - you just need to specify "testa.0.item3" instead of "testa.0"
I would agree with #chridam's comment above though and changing the schema would make the document easier to work with going forward. It might be some extra work now but it will save you in the long run.

Actually you don't have a collection of items, you have a collections of documents which have items as keys:values, if this is the goal, the update may be:
> db.books.update({ "author":"mno" },{$set: {"testa.0.item3":"item3"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.books.find().pretty()
{
"_id" : ObjectId("550c00f81bcc15211016699b"),
"name" : "book3",
"author" : "mno",
"publisher" : "pub",
"testa" : [
{
"item1" : "item1",
"item2" : "item2",
"item3" : "item3"
}
]
}

Related

Update double nested array mongodb

I have the below document which contains double nested array format. I have to update the "level" field to "Senior Engineer" when the "someKey":"somevalue" and "Company":"Company1" and "Name":"Nandhi".
Document
{
"_id" : "777",
"someKey" : "someValue",
"someArray" : [
{
"Company" : "Company1",
"someNestedArray" : [
{
"name" : "Nandhi",
"level" : "Junior Engineer"
},
{
"name" : "Rajan",
"level" : "Senio Engineer"
}
]
}],
{
"Company" : "Company2",
"someNestedArray" : [
{
"name" : "Nandhi",
"level" : "Junior Engineer"
},
{
"name" : "Rajan",
"level" : "Senio Engineer"
}
]
}
]
}
Update Query I tried
db.Test123.updateOne(
{"someKey" : "someValue","someArray.Company":"Company1"},
{$set:{"someArray.$[someNestedArray].level":"Senior Developer"}},
{arrayFilters:[{"someNestedArray.name":"Nandhi"}]}
);
Output Screenshot
As you can seen that, the modifiedCount returns 0. Please advice on this!
You need to define arrayFilter for every level of nesting, try:
db.Test123.update(
{ "someKey" : "someValue" },
{ "$set": { "someArray.$[someArrayDoc].someNestedArray.$[someNestedArrayDoc].level": "Senior Developer" } },
{ arrayFilters: [ {"someArrayDoc.Company": "Company1"}, { "someNestedArrayDoc.name": "Nandhi" } ] }
)

How to update multiple values in nested documents?

I am totally new to MongoDB. I have profiles document and each profile contains languages document.
{
"_id" : ObjectId("5d23134bbd43c3208034f86f"),
"name" : "name1",
"languages" :
[
{
"_id" : ObjectId("5d26321e920fba2c147dec73"),
"language" : "English",
"proficiency" : "elem"
},
{
"_id" : ObjectId("5d2632a5920fba2c147dec74"),
"language" : "Italian",
"proficiency" : "prof"
}
],
"status" : "ACTIVE"
},
{
"_id" : ObjectId("5d231352bd43c3208034f870"),
"name" : "name2",
"languages" :
[
{
"_id" : ObjectId("5d26321e920fba2c147dec75"),
"language" : "Russian",
"proficiency" : "elem"
},
{
"_id" : ObjectId("5d2632a5920fba2c147dec76"),
"language" : "Ukranian",
"proficiency" : "inter"
}
],
"status" : "ARCHIVED"
}
I would like to update all proficiencies in the profiles document (elem -> elementary, inter -> intermediate, prof -> proficient). Any help?
You need $ positional filtered operator
db.col.updateMany({},
{
$set: {
"languages.$[elem].proficiency": "elementary",
"languages.$[inter].proficiency": "intermediate",
"languages.$[prof].proficiency": "proficient",
}
},
{
arrayFilters: [
{ "elem.proficiency": "elem" },
{ "inter.proficiency": "inter" },
{ "prof.proficiency": "prof" },
]
})

Get results in nested objects

This is my collection structure and I want to filter all the results for a defined reference:
{
"_id" : "5xFusfnvRobfMhRKE",
"book" : "Lorem",
"publisher" : "Lorem",
"author" : "Lorem",
"edition" : [
{
"edition" : "Lorem",
"year" : 2015,
"section" : [
{
"pageNumbers" : "12",
"reference" : "4NoHjACkjHJ8mavv9"
}
]
}
]
}
My attempt was Collection.find({'edition.section.reference': '4NoHjACkjHJ8mavv9'}), but that doesn't work. I would expect this matches the above example.
I think this query can help you-
db.collection.find({"edition.section.reference":"4NoHjACkjHJ8mavv9"},{}).pretty()
You have to use 'db' before the collection_name ie. db.collection.find() and for your problem you actually did it right but just missed out on 'db'.
db.sys_test.insert({"-_id":10,"edition":[{"section":[{"reference":"101"}]}]})
db.sys_test.find({"edition.section.reference":"101"}).pretty()
{
"_id" : ObjectId("55faba519d0ff7079e6f9817"),
"-_id" : 10,
"edition" : [
{
"section" : [
{
"reference" : "101"
}
]
}
]
}

Get document based on multiple criteria of embedded collection

I have the following document, I need to search for multiple items from the embedded collection"items".
Here's an example of a single SKU
db.sku.findOne()
{
"_id" : NumberLong(1192),
"description" : "Uploaded via CSV",
"items" : [
{
"_id" : NumberLong(2),
"category" : DBRef("category", NumberLong(1)),
"description" : "840 tag visual",
"name" : "840 Visual Mini Round",
"version" : NumberLong(0)
},
{
"_id" : NumberLong(7),
"category" : DBRef("category", NumberLong(2)),
"description" : "Maxi",
"name" : "Maxi",
"version" : NumberLong(0)
},
{
"_id" : NumberLong(11),
"category" : DBRef("category", NumberLong(3)),
"description" : "Button",
"name" : "Button",
"version" : NumberLong(0)
},
{
"_id" : NumberLong(16),
"category" : DBRef("category", NumberLong(4)),
"customizationFields" : [
{
"_class" : "CustomizationField",
"_id" : NumberLong(1),
"displayText" : "Custom Print 1",
"fieldName" : "customPrint1",
"listOrder" : 1,
"maxInputLength" : 12,
"required" : false,
"version" : NumberLong(0)
},
{
"_class" : "CustomizationField",
"_id" : NumberLong(2),
"displayText" : "Custom Print 2",
"fieldName" : "customPrint2",
"listOrder" : 2,
"maxInputLength" : 17,
"required" : false,
"version" : NumberLong(0)
}
],
"description" : "2 custom lines of farm print",
"name" : "Custom 2",
"version" : NumberLong(2)
},
{
"_id" : NumberLong(20),
"category" : DBRef("category", NumberLong(5)),
"description" : "Color Red",
"name" : "Red",
"version" : NumberLong(0)
}
],
"skuCode" : "NF-USDA-XC2/SM-BC-R",
"version" : 0,
"webCowOptions" : "840miniwithcust2"
}
There are repeat items.id throughout the embedded collection. Each Sku is made up of multiple items, all combinations are unique, but one item will be part of many Skus.
I'm struggling with the query structure to get what I'm looking for.
Here are a few things I have tried:
db.sku.find({'items._id':2},{'items._id':7})
That one only returns items with the id of 7
db.sku.find({items:{$all:[{_id:5}]}})
That one doesn't return anything, but it came up when looking for solutions. I found about it in the MongoDB manual
Here's an example of a expected result:
sku:{ "_id" : NumberLong(1013),
"items" : [ { "_id" : NumberLong(5) },
{ "_id" : NumberLong(7) },
{ "_id" : NumberLong(12) },
{ "_id" : NumberLong(16) },
{ "_id" :NumberLong(2) } ] },
sku:
{ "_id" : NumberLong(1014),
"items" : [ { "_id" : NumberLong(5) },
{ "_id" : NumberLong(7) },
{ "_id" : NumberLong(2) },
{ "_id" : NumberLong(16) },
{ "_id" :NumberLong(24) } ] },
sku:
{ "_id" : NumberLong(1015),
"items" : [ { "_id" : NumberLong(5) },
{ "_id" : NumberLong(7) },
{ "_id" : NumberLong(12) },
{ "_id" : NumberLong(2) },
{ "_id" :NumberLong(5) } ] }
Each Sku that comes back has both a item of id:7, and id:2, with any other items they have.
To further clarify, my purpose is to determine how many remaining combinations exist after entering the first couple of items.
Basically a customer will start specifying items, and we'll weed it down to the remaining valid combinations. So Sku.items[0].id=5 can only be combined with items[1].id=7 or items[1].id=10 …. Then items[1].id=7 can only be combined with items[2].id=20 … and so forth
The goal was to simplify my rules for purchase, and drive it all from the Sku codes. I don't know if I dug a deeper hole instead.
Thank you,
On the part of extracting the sku with item IDs 2 and 7, when I recall correctly, you have to use $elemMatch:
db.sku.find({'items' :{ '$all' :[{ '$elemMatch':{ '_id' : 2 }},{'$elemMatch': { '_id' : 7 }}]}} )
which selects all sku where there is each an item with _id 2 and 7.
You can use aggregation pipelines
db.sku.aggregate([
{"$unwind": "$sku.items"},
{"$group": {"_id": "$_id", "items": {"$addToSet":{"_id": "$items._id"}}}},
{"$match": {"items._id": {$all:[2,7]}}}
])

MongoDB find documents if a property array doesn't contain an object

I have a list of documents like this.
[
{
"name" : "test",
"data" : [
{ "code" : "name", "value" : "Diego" },
{ "code" : "nick", "value" : "Darko" },
{ "code" : "special", "value" : true }
]
},
{
"name" : "another",
"data" : [
{ "code" : "name", "value" : "Antonio" },
{ "code" : "nick", "value" : "Tony" }
]
}
]
now I need to find all the documents that:
a) don't contain a "data" item with code "special"
OR
b) contains a "data" item with code "special" and value false
It's like I needed the opposite of $elemMatch or I'm missing something?
I'm assuming that you're inserting each document in your list of documents as a separate member of a collection test.
For a,
db.test.find({ "data.code" : { "$ne" : "special" } })
For b.,
db.test.find({ "data" : { "$elemMatch" : { "code" : "special", "value" : false } } })
Combining the two with $or,
db.test.find({ "$or" : [
{ "data.code" : { "$ne" : "special" } },
{ "data" : { "$elemMatch" : { "code" : "special", "value" : false } } }
] })
Hope this $nin will solve your issues.
I insertd your docs into "so" collection
db.so.find({}).pretty();
{
"_id" : ObjectId("5489cd4f4cb16307b808d4b2"),
"name" : "test",
"data" : [
{ "code" : "name",
"value" : "Diego"
},
{ "code" : "nick",
"value" : "Darko"
},
{ "code" : "special",
"value" : true
}
]
}
{
"_id" : ObjectId("5489cd674cb16307b808d4b3"),
"name" : "another",
"data" : [
{"code" : "name",
"value" : "Antonio"
},
{ "code" : "nick",
"value" : "Tony"
}
]
}
don't contain a "data" item with code "special"
> db.so.find({"data.code":{$nin:["special"]}}).pretty();
{
"_id" : ObjectId("5489cd674cb16307b808d4b3"),
"name" : "another",
"data" : [
{ "code" : "name",
"value" : "Antonio"
},
{ "code" : "nick",
"value" : "Tony"
}
]
}
contains a "data" item with code "special" and value false
db.so.find({$and:[{"data.code":"special"},{"data.value":false}]}).pretty();