I have a mongo document like this.
{ "_id" : ObjectId("50b429ba0e27b508d854483e"), "array" : [ { "id" : "1", "letter" : "a" }, { "id" : "2", "letter" : "b" } ], "tester" : "tom" }
I want to be able to insert and update the array
with a single mongo command and not use a conditional within a find()
then run insert()
and update()
depending on the presence of the object.
The id
is the item I want to be the selector. So if I update the array with this:
{ "id" : "2", "letter" : "c" }
I have to use a $set
statement
db.soup.update({ "tester":"tom", 'array.id': '2' }, { $set: { 'array.$.letter': 'c' } })
And if I want to insert a new object into the array
{ "id" : "3", "letter" : "d" }
I have to use a $push
statement
db.soup.update({ "tester":"tom" }, { $push: { 'array': { "id": "3", "letter": "d" } } })
I need a sort of upsert for an array item.
Do I have to do this programmatically or can I do this with a single mongo call?
Here in MongoDB, the upsert option is a Boolean value. Suppose the value is true and the documents match the specified query filter. In that case, the applied update operation will update the documents. If the value is true and no documents match the condition, this option inserts a new document into the collection.
You can use the updateOne() or updateMany() methods to add, update, or remove array elements based on the specified criteria. It is recommended to use the updateMany() method to update multiple arrays in a collection.
Unlike relational database models, MongoDB documents can have fields which have values as arrays. The prototypical example in almost all MongoDB documentation is a document having a tags field, whose value is an array of strings, such as ["NoSQL", "Ruby", "MongoDB"] .
Update Nested Arrays in Conjunction with $[]The $[<identifier>] filtered positional operator, in conjunction with the $[] all positional operator, can be used to update nested arrays. The following updates the values that are greater than or equal to 8 in the nested grades. questions array if the associated grades.
I'm not aware of an option that would upsert into an embedded array as at MongoDB 2.2, so you will likely have to handle this in your application code.
Given that you want to treat the embedded array as sort of a virtual collection, you may want to consider modelling the array as a separate collection instead.
You can't do an upsert based on a field value within an embedded array, but you could use $addToSet
to insert an embedded document if it doesn't exist already:
db.soup.update({ "tester":"tom" }, { $addToSet: { 'array': { "id": "3", "letter": "d" } } })
That doesn't fit your exact use case of matching by id
of the array element, but may be useful if you know the expected current value.
I just ran into this problem myself. I wasn't able to find a one-call solution, but I found a two-call solution that works when you have a unique value in your array elements. Use the $pull
command first, which removes elements from an array, and then $push
.
db.soup.update({ "tester":"tom" }, { $pull: { 'array': { "id": "3" } } }) db.soup.update({ "tester":"tom" }, { $push: { 'array': { "id": "3", "letter": "d" } } })
This should work when the document doesn't exist, when the document exists but the entry in the array doesn't exist, and when the entry exists.
Again, this only works if you have something, like the id
field in this example, that should be unique across elements of the array.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With