How update my objects in a document's array in mongoDB - arrays

i have the following collection, I have one question about:
{
"_id" : ObjectId("123456789"),
"user_id" : 123456,
"total" : 100,
"items" : [
{
"item_name" : "my_item_one",
"price" : 30
},
{
"item_name" : "my_item_two",
"price" : 30
},
{
"item_name" : "my_item_three",
"price" : 30
}
]
}
how i can update all price concurrently, (price=50 in all objects)
thanks for help

You can use positional all operator to update all elements in the array
db.collectionName.update(
{ },
{ $set: { "items.$[].price" : 50 } },
{ multi: true }
)

Related

Find all matching elements in the array

Can someone please help me with this query ??
Query >>> Find all warehouses that keep item "Planner" and having in-stock quantity less than 20
This is the sample document in the items collection of the Inventory database :
{
"_id" : ObjectId("6067640da9a907175caaca34"),
"id" : 101,
"name" : "Planner",
"status" : "A",
"height" : 12,
"tags" : [
"mens",
"womens"
],
"warehouses" : [
{
"name" : "Phoenix",
"quantity" : 25
},
{
"name" : "Quickshift",
"quantity" : 15
},
{
"name" : "Poona",
"quantity" : 10
}
]
}
This is what I have tried doing :
db.items.find({"name":"Planner","warehouses.quantity":{"$lt":20}},{"warehouses":1,"_id":0}).pretty()
But it gives me the result as
{
"warehouses" : [
{
"name" : "Phoenix",
"quantity" : 25
},
{
"name" : "Quickshift",
"quantity" : 15
},
{
"name" : "Poona",
"quantity" : 10
}
]
}
Demo - https://mongoplayground.net/p/IpD5ypWSZyt
Use aggregation query
db.collection.aggregate([
{ $match: { "name": "Planner" } },
{ $unwind: "$warehouses" }, // break into individual documents
{ $match: { "warehouses.quantity": { $lt: 20 } } }, // query the data
{ $group: { _id: "_id", warehouses: { $push: "$warehouses" } } } // join them back
])
Demo - https://mongoplayground.net/p/pdTY0IkIqgF
Use $elemMatch only if you think there will be only 1 array element matching per document
The $elemMatch operator matches documents that contain an array field with at least one element that matches all the specified query criteria.
The $elemMatch operator limits the contents of an field from the query results to contain only the first element matching the $elemMatch condition.
db.collection.find({
"name":"Planner",
"warehouses": { "$elemMatch": { "quantity": { $gt: 20 } } }
},
{ "warehouses.$": 1})
https://docs.mongodb.com/manual/reference/method/db.collection.find/#find-projection

Navigate thought a lots of array and update value of object with mongo query

Hey guys I'm trying to update a value that is in an array in MongoDB, am trying to use the mongo queries but is not working, am following the next documentation from Mongo doc
this one is the array:
{
"_id" : "605e3d9b9ef219de662113d0",
"distribution" : [
{
"floor" : 1,
"rooms" : [
{
"number" : 301,
"beds" : [
{
"number" : 818,
"status" : "Vacante Sucia"
},
{
"number" : 819,
"status" : "Vacante Sucia"
}
],
"gender" : "M"
},
{
"number" : 302,
"beds" : [
{
"number" : 820,
"status" : "Vacante Sucia"
},
{
"number" : 821,
"status" : "Vacante Sucia"
}
],
"gender" : "M"
},
{
"number" : 303,
"beds" : [
{
"number" : 822,
"status" : "Vacante Sucia"
},
{
"number" : 823,
"status" : "Vacante Sucia"
}
],
"gender" : "M"
}
]
}
],
"name" : "Meteorologia",
"code" : "METEO"
}
this one is the query that is using in mongoDB to update the status from the bed 801, room 301, floor 1:
in the arrayFilters i specified the index 0 to get the first element of the arrays
db.getCollection('establishments_copy').findAndModify({query: { code: "METEO"}, update: { $set: { "distribution.$[i].rooms.$[i].beds.$[i].status": "TEST"}}, arrayFilters: [{"i.rooms": 0, "i.beds": 0, "i.status": 0}]})
they are returning me the collection but without changes, is possible to navigate validating not for the index just with the values.
for example using the next query:
db.getCollection('establishments_copy').findAndModify({query: { code: 'METEO', distribution: { $elemMatch: { floor: 1, 'rooms.number': 301, 'rooms.beds.number': 818}}}, update: { $set: { '...': 'CHANGED'}}})
thanks!
You just need to create separate condition as per sub document's field name,
f for floor field in distribution array
r for number field in rooms array
b for number field in beds array
db.getCollection('establishments_copy').findAndModify({
query: { code: "METEO"},
update: {
$set: {
"distribution.$[f].rooms.$[r].beds.$[b].status": "TEST"
}
},
arrayFilters: [
{ "f.floor": 1 },
{ "r.number": 301 },
{ "b.number": 818 }
]
})
Playground

Update array at specific index by other filed in MongoDB

I have a collection, consist of name and data.
data is an array with 2 elements, each element is the object with code and qty.
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "a",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "c",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
I want to update the code of the first element to name of its document. The result I want is
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "Anna",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "James",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
I just google to find how to:
update array at a specific index (https://stackoverflow.com/a/34177929/11738185)
db.Collection.updateMany(
{ },
{
$set:{
'data.0.code': '$name'
}
}
)
But the code of the first element in data array is a string '$name', not a value (Anna, James)
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"code" : "$name",
"qty" : 3
},
{
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"code" : "$name",
"qty" : 5
},
{
"code" : "d",
"qty" : 6
}
]
}
update a field by the value of another field. It takes me to use pipeline updating (https://stackoverflow.com/a/37280419/11738185): the second param of updateMany is array (pipeline)
db.Collection.updateMany(
{ },
[{
$set:{
'data.0.code': '$name'
}
}]
)
and It adds field 0 to each element in data array
{
"_id" : ObjectId("605c666a15d2612ed0afedd2"),
"name" : "Anna",
"data" : [
{
"0" : {
"code" : "Anna"
},
"code" : "a",
"qty" : 3
},
{
"0" : {
"code" : "Anna"
},
"code" : "b",
"qty" : 4
}
]
},
{
"_id" : ObjectId("605c666a15d2612ed0afedd3"),
"name" : "James",
"data" : [
{
"0" : {
"code" : "James"
},
"code" : "c",
"qty" : 5
},
{
"0" : {
"code" : "James"
},
"code" : "d",
"qty" : 6
}
]
}
I can't find the solution for this case. Could anyone to help me? How can I update array at fixed index by other field. Thanks for reading!
1. update array at a specific index
You can't use internal fields as value of another fields, it will work only when you have external value to update like { $set: { "data.0.code": "Anna" } }.
2. update a field by the value of another field
Update with Aggregation pipeline can't allow to access data.0.code syntax.
You can try using $reduce in update with aggregation pipeline,
$reduce to iterate loop of data array, set empty array in initialValue of reduce, Check condition if initialValue array size is zero then replace code with name and merge with current object using $mergeObjects, else return current object,
$concatArrays to concat current object with initialValue array
db.collection.update({},
[{
$set: {
data: {
$reduce: {
input: "$data",
initialValue: [],
in: {
$concatArrays: [
"$$value",
[
{
$cond: [
{ $eq: [{ $size: "$$value" }, 0] },
{ $mergeObjects: ["$$this", { code: "$name" }] },
"$$this"
]
}
]
]
}
}
}
}
}],
{ multi: true }
)
Playground
I think easier would be another way.
Just save the model before and use it for updating after
var annaModel = nameModel.findOne({_id: "605c666a15d2612ed0afedd2" })
nameModel.findOneAndUpdate({_id: "605c666a15d2612ed0afedd2"},{$set:{'data.0.code': annaModel.name}})

update nested array element value in node js mongoDB [duplicate]

This question already has answers here:
How to Update Multiple Array Elements in mongodb
(16 answers)
Closed 6 years ago.
Hi i am new in nodejs i need to update a value in nested array using _id of document my database document is look like this..
"complaints" : [
{
"complaint" : "head light is not working",
"complaintid" : ObjectId("57205219a56d2b8c0f9274a4"),
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"labour" : 350,
"partCost" : 0,
"part" : [
{
"id" : ObjectId("56f12eaab915bd9800272ed7"),
"estimate" : 450,
"partname" : "clutch",
"_id" : ObjectId("57454cef49218eb40c1c0d25"),
"quantity" : 0,
"qrcodes" : []
},
{
"id" : ObjectId("56f12eaab915bd9800272ed7"),
"estimate" : 450,
"partname" : "rear tyre",
"_id" : ObjectId("57454cef49218eb40c1c0d24"),
"quantity" : 0,
"qrcodes" : []
}
],
"acceptance" : true,
"inspection" : false,
"color" : "#8929A9",
"status" : "APPROVED",
"estimate" : 1200,
"solution" : "HEAD LIGHT CHANGE",
"problems" : "HEAD LIGHT IS NOT WORKING"
},
i need to update quantity value of part array exist inside the part array using _id of part array
i am trying this but its not working what should i do for update this value...
var partdata = req.payload.parts;
for(var k = 0; k< partdata.length ; k++ ){
CPS.update({
'complaints.part._id' : partdata[k].partid
}, {
"$inc" : {
'complaints.part.$.quantity' : partdata[k].quantity
}
}).exec
(function(err,temp) {
if(err){
res(err).code(500);
}else{
console.log(temp);
}
});
}
MongoDB doesn't support matching into more than one level of an array.
Consider altering your document model so each document represents an
operation, with information common to a set of operations duplicated
in the operation documents.
Following is not the solution for your case.
But in-case you know the index then you could do something like this:
Assume a sample document like:
{
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"part" : [{ "quantity" : 111 }, { "quantity" : 222 }]
}
Then this query should work.
db.test.update({ "_id" : ObjectId("57454c9249218eb40c1c0d1f") }, { "$set" : { "part.1.quantity" : 999 } })
Document will get modified as follows :
{
"_id" : ObjectId("57454c9249218eb40c1c0d1f"),
"array" : [{ "quantity" : 222 }, { "quantity" : 999 }]
}
Update: You can try following way of doing the update. But its not recommended way of doing probably you need to restructure your schema.
db.test.aggregate([
{ "$unwind": "$complaints" },
{ "$unwind": "$complaints.part" },
{ "$project":
{
_id: "$complaints.part._id",
partqty: "$complaints.part.quantity"
}
},
]);
This should return as follows:
{
"_id" : ObjectId("57454cef49218eb40c1c0d25"),
"partqty" : 111
}
{
"_id" : ObjectId("57454cef49218eb40c1c0d24"),
"partqty" : 222
}
Now you can use this information to update, e.g
var cur = db.test.aggregate([
{ "$unwind": "$complaints" },
{ "$unwind": "$complaints.part" },
{ "$project":
{
_id: "$complaints.part._id",
partqty: "$complaints.part.quantity"
}
},
]);
while (cur.hasNext()) {
var doc = cur.next();
//Note the index should be know again :|
db.test.update({ "complaints.part._id": ObjectId("57454cef49218eb40c1c0d25") },
{ "$set": { "complaints.$.part.1.quantity": 55 }},
{ "multi": true})
}

Conditionally remove Subdocument nested inside array of document MongoDB

I have a collection with document like this:
{
"_id" : "ABC",
"Name" : "Rajesh",
"createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
"updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
"AvgValue" : "65",
"PreValues" : [
{
"Date" : 20150709,
"Rate" : [
{
"Time" : 1566,
"value" : 60
},
{
"Time" : 1500,
"value" : 400
},
{
"Time" : 1400,
"value" : 100
},
{
"Time" : 1500,
"value" : 103
}
]
}
]
}
I want to remove the duplicate doc for a particular Date value
eg If Time value is 1500, I need to pull the document and push it the new value for (Value) in single bulk operation.
Here is my query
bulk.find({ "_id":"ABC" })
.update(
{
"_id": "ABC",
"PreValues": { "Date": 20150709 }
},
{
$pu‌​ll: { "PreValues": { "Rate": { "Time": 1000 } } }
}
);
bulk.find({ "_id":"ABC" })
.update(
{ "_id": "ABC","PreValues": { "Date": 20150709 }},
{ $pu‌​sh : {
"PreValues": { "Rate": { "Time": 1000,"Rating": 100 }}
}}
);
bulk.execute();
It's not a great idea to have nested arrays since the only thing you will ever be able to do atomically is $push or $pull. See the positional $ operator for details on why "nested arrays" are not good here, but basically you can only ever match the position of the "outer" array element.
And that is basically what you are missing here, and of course the proper "dot notation" for accessing the elements:
var bulk = db.ABA.initializeOrderedBulkOp();
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
.updateOne({ "$pull": { "PreValues.$.Rate": { "Time": 1500 } } })
bulk.find({ "_id": "ABC", "PreValues.Date": 20150709 })
.updateOne({ "$push": { "PreValues.$.Rate": { "Time": 1500, "Rating": 100 } } })
bulk.execute();
Which alters the document like so:
{
"_id" : "ABC",
"Name" : "Rajesh",
"createstmp" : ISODate("2015-06-22T17:09:16.705Z"),
"updstmp" : ISODate("2015-06-22T19:31:53.527Z"),
"AvgValue" : "65",
"PreValues" : [
{
"Date" : 20150709,
"Rate" : [
{
"Time" : 1566,
"value" : 60
},
{
"Time" : 1400,
"value" : 100
},
{
"Time" : 1500,
"Rating" : 100
}
]
}
]
}
That is the correct syntax for both statements there and sends both requests to the server at the same time with a single response.
Note that you need to inclide in the .find() query a field from the outer array to match. This is so the positional $ operator is populated with the matched index of that element and the operator knows which array element to act upon.

Resources