We have to update the bulk values in different arrays.
Is there any way, we can update the values inside the different arrays at the same time ?
Currently, I have the path of the array, Old value and new values, I need to update lot of documents inside one collection - please do let me know if there is a way to do it in Mongodb 3.6 version.
For example:
Path in the collection Old Value New Value
orderDocument.customerOrderItems.customerOrderSubItems.productId 10001 10002
orderDocument.customerOrderItems.customerOrderSubItems.productName Upto 2 Tst/1 Tst Upto 33 Tst/22 Tst
Please share your document structure so we can provide more specific direction. Assuming your document looks like:
{
"orderDocument": {
"customerOrderItems": {
"customerOrderSubItems": [
{
"productId": 10004.0
}
]
}
}
}
Reach the array through a path where value needs to be changed then use the '$' and name of the property to be updated:
db.getCollection('Event').updateMany(
{
"orderDocument.customerOrderItems.customerOrderSubItems.productId": 10004
},
{
$set: {
"orderDocument.customerOrderItems.customerOrderSubItems.$.productId": 10005
}
}
)
This gives the result.
Related
Use case
Adding a field to a specific object in an array of objects using updateOne during a bulkUpdateOps
Blockers
I have been unable to find a way to identify and update a specific object in the subdocument array of a specific record.
I only have access to this DB through MongoDB Compass, and I plan to use the provided mongosh tool.
Data example
Our purchaseorders model looks like this:
{
_id: uuid,
...rest,
documents:[
{
_id:uuid,
forignKey2:string (optional),
keyIWantToAdd:string (optional),
...rest
}
]
}
So if I have
{
_id:*1,
documents:[
{
_id:*2,
forignKey2:'no-test',
...rest
},
{
_id:*3,
forignKey2:'test',
...rest
},
]
}
I want to add a key and value like this (really I'm willing to do anything to set these values, this is just the closest I have been able to get):
var bulkUpdateOps = db.purchaseorders.initializeOrderedBulkOp();
bulkUpdateOps.find('*1').updateOne({
$set:{
documents.[index of document object with forignKey2:'test' or _id:*3 whichever is easier].keyIWantToAdd:'valueIWantToAdd'
}
})
bulkUpdateOps.execute();
Any help or suggestions would be greatly appreciated.
#rickhg12hs posted exactly what I was looking for. For anyone else using mongodb.com/docs/manual/reference/method/Bulk.find.arrayFilters the bulk find is being ran on an array of objects like this: { grades:[ { grade: 85, mean: number } ] }
{
questions: {
q1: "",
}
}
result after updating:
{
questions: {
q1: "",
q2: ""
}
}
I want to add q2 inside questions, without overwritting what's already inside it (q1).
One solution I found is to get the whole document, and modify it on my backend, and send the whole document to replace the current one. But it seems really in-effiecient as I have other fields in the document as well.
Is there a query that does it more efficiently? I looked at the mongodb docs, didn't seem to find a query that does it.
As turivishal said, you can use $set like this
But you also can use $addFields in this way:
db.collection.aggregate([
{
"$match": {
"questions.q1": "q1"
}
},
{
"$addFields": {
"questions.q2": "q2"
}
}
])
Example here
Also, reading your comment where you say Cannot create field 'q2' in element {questions: "q1"}. It seems your original schema is not the same you have into your DB.
Your schema says that questions is an object with field q1. But your error says that questions is the field and q1 the value.
I have a database like this:
{
"universe":"comics",
"saga":[
{
"name":"x-men",
"characters":[
{
"character":"wolverine",
"picture":"618035022351.png"
},
{
"character":"wolverine",
"picture":"618035022352.png"
}
]
}
]
},
{
"universe":"dc",
"saga":[
{
"name":"spiderman",
"characters":[
{
"character":"venom",
"picture":"618035022353.png"
}
]
}
]
}
And with this code, I update the field where name: wolverine:
db.getCollection('collection').findOneAndUpdate(
{
"universe": "comics"
},
{
$set: {
"saga.$[outer].characters.$[inner].character": "lobezno",
"saga.$[outer].characters.$[inner].picture": "618035022354.png"
}
},
/*{
"saga.characters": 1
},*/
{
"arrayFilters": [
{
"outer.name": "x-men"
},
{
"inner.character": "wolverine"
}
],
"multi":false
}
)
I want to just update the first object where there is a match, and stop it.
For example, if I have an array of 100,000 elements and the object where the match is, is in the tenth position, he will update that record, but he will continue going through the entire array and this seems ineffective to me even though he already did the update.
Note: if I did the update using an _id inside of universe.saga.characters instead of doing the update using the name, it would still loop through the rest of the elements.
How can I do it?
Update using arrayFilters conditions
I don't think it will find and update through loop, and It does not matter if collection have 100,000 sub documents, because here is nice explanation in $[<identifier>] and has mentioned:
The $[<identifier>] to define an identifier to update only those array elements that match the corresponding filter document in the arrayFilters
In the update document, use the $[<identifier>] filtered positional operator to define an identifier, which you then reference in the array filter documents. But make sure you cannot have an array filter document for an identifier if the identifier is not included in the update document.
Update using _id
Your point,
Note: if I did the update using an _id inside of universe.saga.characters instead of doing the update using the name, it would still loop through the rest of the elements.
MongoDB will certainly use the _id index. Here is the nice answer on question MongoDB Update Query Performance, from this you will get an better idea on above point
Update using indexed fields
You can create index according to your query section of update command, Here MongoDB Indexes and Indexing Strategies has explained why index is important,
In your example, lets see with examples:
Example 1: If document have 2 sub documents and when you update and check with explain("executionStats"), assume it will take 1 second to update,
quick use Mongo Playground (this platform will not support update query)
Example 2: If document have 1000 sub documents and when you update and check with explain("executionStats"), might be it will take more then 1 second,
If provide index on fields (universe, saga.characters.character and saga.characters.picture) then definitely it will take less time then usual without index, main benefit of index it will direct point to indexed fields.
quick use Mongo Playground (this platform will not support update query)
Create Index for your fields
db.maxData.createIndex({
"universe": 1,
"saga.characters.character": 1,
"saga.characters.picture": 1
})
For more experiment use above 2 examples data with index and without index and check executionStats you will get more clarity.
I am working on a mongo statement for adding and updating values into an object within my document.
Here is my current statement. field and value changes depending what is getting passed in:
db.collection.update(id, {
$set: {
analysis : {[field]: value}
}
});
Here is an example of what a document could look like(there are potentially 20+ fields in analysis)
{
_id
analysis:{
interest_rate: 22
sales_cost: 4000
value: 300
}
}
The problem is that every time I update the object all fields are removed except the the field I updated.
so if
field = interest_rate
and the new
value = 33
my document would end up looking like this and all the other fields in analysis would be removed:
{
_id
analysis:{
interest_rate: 33
}
}
Is there a way to update fields within an object like this to keep the code simple or will I have to write out update statements for each individual field?
You should use the dot notation to build the path when you're trying to update nested field. Try:
let fieldPath = 'analysis.' + field; // for instance "analysis.interest_rate"
db.collection.update(id, {
$set: {
fieldPath: value
}
});
Otherwise you're just replacing existing analysis object.
I have a MongoDB document with a structure like this:
{
testValue: 10,
maxValue: 20
}
I want to set testValue to an arbitrary integer value between 0 and maxValue. Ideally, I would do something like this:
db.collection.update(
{},
{
$set: { 'testValue': newValue },
$min: { 'testValue': 0 },
$max: { 'textValue': $maxValue }
}
)
But that obviously doesn't work. There are a handful of threads that relate to this question (e.g. Update MongoDB field using value of another field), but they're all a few years old, and I can't find pertinent information in the official documentation. Is there a way to do what I want, or do I have to use find() to get maxValue then do a separate call to the database using update()?
This is still not possible in Mongo 3.2 or lower, check for example these JIRA tickets:
Self referential updates
Allow update to compute expressions using referenced fields