[SERVER-1243] New operator to update all matching items in an array Created: 16/Jun/10  Updated: 06/Apr/23  Resolved: 11/Aug/17

Status: Closed
Project: Core Server
Component/s: Querying, Write Ops
Affects Version/s: None
Fix Version/s: 3.5.12

Type: New Feature Priority: Major - P3
Reporter: Tim Nelson Assignee: Tess Avitabile (Inactive)
Resolution: Done Votes: 443
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Attachments: PDF File Design Array updates.pdf    
Issue Links:
Depends
depends on SERVER-27089 Extend the update subsystem to suppor... Closed
depends on SERVER-6399 Refactor update() code Closed
is depended on by SERVER-828 Support for selecting array elements ... Closed
Duplicate
is duplicated by SERVER-12680 Cannot unset from all items in array Closed
is duplicated by SERVER-29065 multiple object update in array field Closed
is duplicated by SERVER-29101 how to use $elemMatch with $in operat... Closed
Related
is related to SERVER-19278 How to update multiple array elements... Closed
Backwards Compatibility: Fully Compatible
Participants:

 Description   
Issue Status as of Aug 11, 2017

FEATURE DESCRIPTION
MongoDB 3.5.12 extends all update modifiers to apply to all array elements or all array elements that match a predicate, specified in a new update option arrayFilters. This syntax also supports nested array elements.

VERSIONS
This new feature is available starting with the MongoDB 3.5.12 development version, and included in the MongoDB 3.6 production version.

OPERATION

Update all documents in array

db.coll.update({}, {$set: {“a.$[].b”: 2}})
Input: {a: [{b: 0}, {b: 1}]}
Output: {a: [{b: 2}, {b: 2}]}

Update all matching documents in array

db.coll.update({}, {$set: {“a.$[i].b”: 2}}, {arrayFilters: [{“i.b”: 0}]})
Input: {a: [{b: 0}, {b: 1}]}
Output: {a: [{b: 2}, {b: 1}]}

Update all matching scalars in array

db.coll.update({}, {$set: {“a.$[i]”: 2}}, {arrayFilters: [{i: 0}]})
Input: {a: [0, 1]}
Output: {a: [2, 1]}

Update all matching documents in nested array

db.coll.update({}, {$set: {“a.$[i].c.$[j].d”: 2}}, {arrayFilters: [{“i.b”: 0}, {“j.d”: 0}]})
Input: {a: [{b: 0, c: [{d: 0}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}
Output: {a: [{b: 0, c: [{d: 2}, {d: 1}]}, {b: 1, c: [{d: 0}, {d: 1}]}]}

Update all scalars in array matching a logical predicate

db.coll.update({}, {$set: {“a.$[i]”: 2}}, {arrayFilters: [{$or: [{i: 0}, {i: 3}]}]})
Input: {a: [0, 1, 3]}
Output: {a: [2, 1, 2]}

Each array filter must be a predicate over a document with a single field name. Each array filter must be used in the update expression, and each array filter identifier $[<id>] must have a corresponding array filter. <id> must begin with a lowercase letter and not contain any special characters. There must not be two array filters with the same field name.

IMPLEMENTATION DETAILS
The implementation of this feature involved a rewrite of the update system. Users can find all the related tickets here. The design document is attached.

Original description


 Comments   
Comment by Asya Kamsky [ 02/Sep/17 ]

Note that to avoid examining every document and update only the ones that match "YUAN" you can include a query for the update statement - instead of {} use {"accounts.currency":"YUAN"}

Comment by Tess Avitabile (Inactive) [ 01/Sep/17 ]

The update command modifies the first matching document by default. To modify multiple documents, you must use the parameter multi:true, which is documented here.

Comment by KEYUR Patel [ 31/Aug/17 ]

Hi Asya,

Sorry I was not clear. Yes it did modified first record available when I executed that Update command.

but I want to update all the documents inside Accounts and for all the customers who has these accounts. Should not this command update all ?

Comment by Asya Kamsky [ 31/Aug/17 ]

keyurpatel80@gmail.com this would happen if no element of the "accounts" array had a subdocument matching "currency" "YUAN".

I ran your update statement on a document with such currency present and it worked fine:

db.bank_data.update({},{$set: {"accounts.$[i].currency" : "CAD"}} ,{arrayFilters: [ {"i.currency": "YUAN"}]})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
// note that running it the second time doesn't match anything as all "YUAN" values were already changed to "CAD"
db.bank_data.update({},{$set: {"accounts.$[i].currency" : "CAD"}} ,{arrayFilters: [ {"i.currency": "YUAN"}]})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 })

Comment by KEYUR Patel [ 31/Aug/17 ]

Hi Tess,
Thanks I enabled the featureCompatibilityVersion to 3.6 by this command

db.adminCommand(

{setFeatureCompatibilityVersion: "3.6"}

)

and I used this to update my all the documents which has currency as "YUAN" to "CAD" but it does not update all the documents. What is missing here ?

> db.bank_data.update({},{$set: {"accounts.$[i].currency" : "CAD"}} ,{arrayFilters: [

{"i.currency": "YUAN"}

]})
WriteResult(

{ "nMatched" : 1, "nUpserted" : 0, "nModified" : 0 }

)

Comment by Tess Avitabile (Inactive) [ 31/Aug/17 ]

Hi keyurpatel80@gmail.com,

The featureCompatibilityVersion must be 3.6 in order to use this feature. featureCompatibilityVersion is a setting that we use to prevent usage of features that would break in a mixed-version cluster. The documentation page for featureCompatibilityVersion is not yet available in 3.6, but it will look similar to our documentation page for featureCompatibilityVersion in 3.4, which is here. Essentially, when the featureCompatibilityVersion is 3.6, that is a guarantee that all nodes in the cluster have a binary version of at least 3.6, so it is safe to use features that would break if there were 3.4 nodes in the cluster.

You can set the featureCompatibilityVersion to 3.6 by running

db.adminCommand({setFeatureCompatibilityVersion: "3.6"})

Then you will be able to use the new arrayFilters features. Thanks for trying out the new feature!

Tess

Comment by KEYUR Patel [ 31/Aug/17 ]

Thanks. I tried 3.5.12 Dev version but it still did not work. Looks like I need to wait for official 3.6 version.

> db.bank_data.update({},{$set: {"accounts.$[i].currency" : "CAD"}} ,{arrayFilters: [

{"i.currency": "YUAN"}

]})
WriteResult({
"nMatched" : 0,
"nUpserted" : 0,
"nModified" : 0,
"writeError" :

{ "code" : 72, "errmsg" : "The featureCompatibilityVersion must be 3.6 to use arrayFilters. See http://dochub.mongodb.org/core/3.6-feature-compatibility." }

})

Comment by Ramon Fernandez Marina [ 18/Aug/17 ]

keyurpatel80@gmail.com, thanks for your interest in this new feature. MongoDB development release 3.5.12 is scheduled for publication next week (week of August 21st), so it should be available in the coming days.

Please subscribe to mongodb-announce to get notifications about MongoDB releases.

Thanks,
Ramón.

Comment by KEYUR Patel [ 18/Aug/17 ]

Hi,
Where I can download 3.5.12 for osx ? I tried binary page here. https://www.mongodb.org/dl/osx

but there is no 3.5.12

Comment by Asya Kamsky [ 21/Jun/17 ]

We were specifically looking for syntax that was not involved in the match expression. In other words, the match specifies which document(s) is to be updated only. The arrayFilters specifies which array elements are updated.

This solution addresses this as well as SERVER-831.

Comment by Adam Reis [ 20/Jun/17 ]

Hi Asya,

Great to see progress on these array issues. Quick question though; from the posted examples it looks like this will work through options, rather than in the match portion of the update command. Is there a particular technical reason behind this decision?

It would be more intuitive to handle this in the match portion, e.g. something along the lines of:

db.coll.update(

{'a.b': 0}

, {$set: {"a.$[i].b": 2}});

or if the `i` is needed:

db.coll.update(

{'a.$[i].b': 0}

, {$set: {"a.$[i].b": 2}});

Is there a technical limitation preventing a solution like this?

Comment by Asya Kamsky [ 20/Jun/17 ]

Hi all,

We are currently making progress on a solution to this issue under SERVER-27089. Since this feature is still in development, and not yet switched on in a development release, we don't yet have documentation for how it will work. But to give you a quick preview, you will be able to update all matching values or subdocuments in an array as follows:

db.coll.update({}, {$set: {"a.$[i].b": 2}},  {arrayFilters: [{"i.b": 0}]});
 
Input: {a: [{b: 0}, {b: 1}, {b:0}]}
Output: {a: [{b: 2}, {b: 1}, {b:2}]}

We will post a more formal update on SERVER-27089 when this work is complete.

Best,
Asya

Comment by Yannick Bétemps [X] [ 14/Jun/17 ]

A way to implement this ticket would be to add an new "$update" command in the aggregation pipeline toolset.
This would be quite usefull many ways, by the way.

Like the "$out" it should be the last step of the pipeline, it could also have the same syntax that regular "update" function but using data available in the aggregation stack instead, it could also work in a similar way to the "$lookup" stage.

So for the example of the comments to update : I would do a $match, then $project the comment array, $unwind it then calling the new $update stage with three objects as a setting : the match part, the update part and the options part, and off course the $update would use the lines of the current result set to do updates, just like sql does.

No retro-compatibility problem
Lots of use (and sorry I did not check if this request exists elsewhere)

Comment by majid ali [ 14/Jun/17 ]

any update on this ticket ? i extremely need it for my project

Comment by Pham Cuong [ 14/Mar/17 ]

Waiting !!!!!!!!!!

Comment by Nuno [ 21/Nov/16 ]

Help

Comment by Ritesh Agarwal [ 21/Nov/16 ]

Hi,

Can this feature be implemented, as we are using nodejs with mongoDb, and fetching large dataset on node thread is very expensive. If there can be a query where all the elements in an embedded array gets updated in one click, it would be a very useful query.

Thanks
Ritesh

Comment by bakti [ 04/Oct/16 ]

come on guys, you can do it

Comment by Jonathan [ 25/Aug/16 ]

We understand that it's not a small change, but the fact that the platform is unable to do basic operations like this is super lame. Come on Mongo...

Comment by Adam Reis [ 18/Jul/16 ]

Perhaps it's left unfixed intentionally, given how most MongoDB hosts charge you by the number of operations you perform...

Comment by Grant Miller [ 18/Jul/16 ]

Definitely disappointed as well. As others have said, inability to do this goes against the entire idea of MongoDB. I honestly thought something was broken when it didn't work, such a basic requirement.

What do the developers propose as a workaround? Save I have 5 comments and want to mark all as read, how would I write that query? 5 updates?

Comment by Ravi [ 14/Jul/16 ]

Yes I also felt, this is some thing missing in MongoDB

Comment by joymufeng [ 13/Jul/16 ]

Yes, it's a must-have feature.

Comment by Adam Reis [ 08/Jul/16 ]

Well, guess I'm late to the party, but it's still very disappointing to find out that this issue hasn't been addressed in 6 years time.
Basically what has been said above:

> As much as I love this database in general, it is embarrassing that this very fundamental and must-have feature (especially because this approach is recommended per design of mongo) is still not available after 5 years! It doesn't matter how you implement it, it will still be faster as to do it in the code.

After reading a MongoDB blog about denormalization, I thought I'd give it a go and see how it works. Everything was going great until I had to do an update in an array of denormalized data, and then I realized it's impossible to do with one query.

This is really a must have feature, especially if you're recommending data denormalization in your blogs.

PS: What's even more problematic, is that this doesn't just not work for updating multiple items in one array, it also doesn't work for updating a single item in an array for multiple documents.

Comment by Sergio Rykov [ 11/May/16 ]

Aggreed. From time to time have to do the same thing again and again - and watch what's new - Nothing changed.

PMs of MongoDB - please consider to add it to nearest backlog or provide copy-paste'able workaround and schedule it vNext + 1 release .

Base workaround uses optimistic locking http://stackoverflow.com/questions/8505489/multiple-update-of-embedded-documents-properties , but it's not what I want to do repeatedly.

Comment by riccardo salzer [ 26/Nov/15 ]

In my opinion this missing feature breaks the the whole concept of MongoDB. Its meant to nest all information I need to the place where I need it, mostly as an array of subdocuments and what if this is for example user information inside comments. the user changes his image and one has to update all of those subdocuments inside of all comments. MongoDB also recommend this method in their conferences. But actually, if you do this, how is one supposed to update all those information afterwards if something changes?
As much as I love this database in general, it is embarrassing that this very fundamental and must-have feature (especially because this approach is recommended per design of mongo) is still not available after 5 years! It doesn't matter how you implement it, it will still be faster as to do it in the code.

Comment by Jeremy Martin [ 26/Aug/15 ]

There is one possible workaround, which I didn't see mentioned, and that would be to read the full (matched) document, create a targeted update to the array elements to change, and then updating the document only if no other changes have been made to the field (array) being updated.

Unless I'm missing something, this seems tantamount to read-update-write with two-phase commit, right? Maybe it's not technically the same, but it provides equal burden on the client to ensure the correctness of the transaction. And, just like in two-phase commit, a real-world application of this technique would require retry logic if the array actually had been updated in the meantime, resulting in yet another query (on top of the initial one that already feels superfluous for an update operation). And this becomes exponentially more problematic when updating highly contentious resources.

I would like to caution folks that if you have many documents with huge arrays, it's likely not an efficient schema design if you need to be querying and updating multiple array elements (especially if the array is indexed).

I of course would have to agree with this, but this is ultimately a problem class that is independent of dataset size.

Alright, obviously I'm frustrated. After 5 years and a hundred comments, I guess this just is what it is. And I honestly don't want to belabor a bunch of points about transactions and atomicity that I know you (Asya) understand at a much deeper level than me. It just seems like Mongo in general can get fuzzy on this topic. I.e., there's a lot of advice to put things in separate documents if you need certain update semantics, and to put them into the same document if you need certain transaction semantics, and then things get kind of hand wavy if you need both.

I get that no database can be "all things to all users", but this one is perplexing. We're not talking about actually changing transactional or atomicity semantics at all. We simply need a way to utilize those existing semantics via an extension of the query language. I'm not claiming it's trivial, but it doesn't seem intractable, either.

Comment by Jaan Paljasma [ 26/Aug/15 ]

To be fair and square - I am disappointed. The feature has been up for several years, and I agree with jacaetevha that the community has done all they could to raise awareness.
Having many documents with huge arrays is the whole point of the noSQL Document schema. For key-value storage (or key-object) there are faster and more scalable systems out there.

Comment by Noah [X] [ 26/Aug/15 ]

Thank you asya for your reply and insight into the challenges of this feature.

Comment by Jason Rogers [ 26/Aug/15 ]

to jmar777's response. Honestly asya, at this point saying...

We do recognize the interest the community is expressing via this ticket and we do take this input into consideration during project planning.

... seems like a blowoff. You may not have meant it that way, but after 5 years I'm not sure what else you expect the community to get from that. Perhaps the community does not have a loud enough voice in regards to this feature request.

Comment by Asya Kamsky [ 26/Aug/15 ]

There've been several workarounds mentioned on this thread. I want to point out that one of the desirable features of the workaround that's more important than performance must be correctness. This means that you must make sure that your query predicate is an exact match to the element you want to update ("elements" in the future). Than means ensuring that your query predicate matches only elements you want to change and does not match elements you don't want to change.

There is one possible workaround, which I didn't see mentioned, and that would be to read the full (matched) document, create a targeted update to the array elements to change, and then updating the document only if no other changes have been made to the field (array) being updated.

This has the advantage of only updating the array if it has not been modified since we read it, which is key for atomicity and correctness in multithreaded environments – see the example that follows.

Assuming our collection "coll" has documents which have a field named "arr" which is an array where "a2" is an field that may have "old" value which needs to be set to "new", the following is code in the shell to do that to a single document:

 
> docOrig=db.coll.findOne({"_id":1, "arr.a2":"old"},{"arr":1})
{
	"_id" : 1,
	"arr" : [
		{
			"a1" : 0,
			"a2" : "old"
		},
		{
			"a1" : 1,
			"a2" : "ok"
		},
		{
			"a1" : 2,
			"a2" : "old"
		},
		{
			"a1" : 3,
			"a2" : "new"
		}
	]
}
> updatedFields={}
{ }
> for (i=0; i<docOrig.arr.length; i++) {
     if (docOrig.arr[i].hasOwnProperty("a2") && updatedFields.arr[i].a2=="old") {
               updatedFields["arr."+i+".a2"]="new"; 
} }
new
> db.coll.update(docOrig, {"$set":updatedFields})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> print(tojsononeline(docOrig))
{  "_id" : 1,  "arr" : [ { "a1" : 0, "a2" : "old" }, { "a1" : 1, "a2" : "ok" }, { "a1" : 2, "a2" : "old" }, { "a1" : 3, "a2" : "new" } ] }
> print(tojsononeline(db.coll.findOne({"_id":1},{"arr":1})))
{  "_id" : 1,  "arr" : [ { "a1" : 0, "a2" : "new" }, { "a1" : 1, "a2" : "ok" }, { "a1" : 2, "a2" : "new" }, { "a1" : 3, "a2" : "new" } ] }

The above reads in the array of the document (that needs multiple elements updated), iterates over the array while creating a single "update" (using "$set") and then runs the update conditionally only if the document (technically, if the "arr" field of the document) has not been changed since we read it.

There is a single atomic update which updates appropriate elements of the arr array with new values. Another approach could be constructed to create a totally new "arr" field for the document and do an update that replaces the "arr" field with a new array - depending on what percentage of array's fields are being changed, this may turn out to be more efficient in case where majority of array elements are being set to new value.

I would like to caution folks that if you have many documents with huge arrays, it's likely not an efficient schema design if you need to be querying and updating multiple array elements (especially if the array is indexed).

Asya

Comment by Jeremy Martin [ 26/Aug/15 ]

Edit: sorry, accidentally submitted prematurely.

and in short is a matter of prioritization

5 years and two months later, that more-or-less was implicit at this point...

This really is a shame, though. The absence of multi-document, atomic transactions, often drive schema design towards storing data that requires atomic updates in a single document. Even the documentation suggests this:

Since a single document can contain multiple embedded documents, single-document atomicity is sufficient for many practical use cases.

However, the utility of "multiple embedded documents" (especially in an array) is severely limited due to the lack of any reasonable utilities for mutating them. This in turn requires read-update-write cycles, which ultimately requires two-phase commit logic being burdened on the consuming applications. As much as I've been a proponent for MongoDB over the years, I've run into more and more situations where this specific issue has ultimately driven me to look elsewhere.

I don't mean this to sound too ranty, but it can be difficult to work around MongoDB's generally cavalier approach to the transactional needs of applications, and it's honestly frustrating to wait 5 years just to hear "it's hard" and "not a priority".

Comment by Asya Kamsky [ 26/Aug/15 ]

Folks,

We appreciate the challenge of maintaining applications using schemas with large arrays, especially with respect to updating many or all array elements, and we very much recognize the interest from the community around this ticket.

Unfortunately, to implement such a new feature, there are major requirements:

  • a specification for new language feature (like update modifiers or expressions), since we cannot break existing uses
  • should be included with support to match all array elements, as well was those matching a query
  • requests for support to update the last element(s) should be considered.
  • must support all existing update modifiers (correctly, and in a non-backwards-breaking way) including $rename, $set, $unset, $pull, $push, $bit...
  • must work efficiently with all arrays, including large ones having thousands of elements
  • cannot change current update semantics or behaviors which existing applications and deployments depend on (= non-backwards-breaking).

In summary, adding this as a new feature is not trivial. It will require resources which are currently working on other projects, and in short is a matter of prioritization over other parts of the whole server.

We do recognize the interest the community is expressing via this ticket and we do take this input into consideration during project planning.

Asya Kamsky
Lead Product Manager
MongoDB Server

Comment by Lucas Geiger [ 26/Aug/15 ]

Agree with Fabio. This is a deal breaker when the proposed advantage of mongo is using nested fields in a performant manner. Other workarounds introduce too much risk.

Comment by Fabio Sussetto [ 19/Aug/15 ]

Show stopper for me when I was evaluating mongodb for a project. An set of efficient operations to manipulate denormalised data is key when you need to decide relational vs non-relational.
It's worrying that this issue has been open for 5 years without any clear decision on this.
If you guys decide this is out of scope and you don't want to implement this, fine, but there should be a red warning in the docs saying this is a limitation.

Comment by Khaled Ayoubi [ 18/Aug/15 ]

Just started exploring MongoDB last week, and I run into this very quick

Comment by Reinhard Handler [ 06/Aug/15 ]

I'm too missing this feature as there is no acceptable workaround available.

Comment by Christopher Hranj [ 01/Jul/15 ]

I just ran into this issue during my first time ever using a database. The use case for this is very evident. Please assign someone to this. It's been five years....

Comment by Rajesh Kumar [X] [ 30/Jun/15 ]

Really need this feature in MongoDB while doing bulk update

Comment by Sergei Bershadsky [X] [ 25/Jun/15 ]

Really missing this feature

Comment by Richard Brookfield [ 16/Jun/15 ]

Can someone from the Mongo team report when they think they will be able to assign someone to this issue? Please and Thank you!

Comment by Sudhakar Reddy [ 29/May/15 ]

The lack of support/workarounds on this from the mongodb team is ridiculous.
Updating more than one element in an array is clearly a common requirement.
and yet its been here for years as a minor issue. !!!

Comment by Xiaoning Chen [ 17/Apr/15 ]

How to let Mongodb know it is such an important missing feature needed by many people. The array operation isn't powerful enough to handle use cases. Please seriously consider users needs.

Comment by Foo Bar 2rd [ 13/Apr/15 ]

For me this is such an important core feature it seems very odd it hasn't been implemented yet.

Comment by Pierre Bazoge [ 09/Apr/15 ]

Could be nice to have an operator like $$ or $all to update all the subdocs. Thanks for the priority update by the way.

Comment by Jose Miguel Díez de la Lastra [ 09/Apr/15 ]

Priority changed! Thank you.

Comment by Jochen Brüggemann [ 08/Apr/15 ]

+1 We are ALL waiting for it. Just do it!

Comment by Jaan Paljasma [ 07/Apr/15 ]

Almost 5 years in Feature request and still not implemented? Considering the # of votes and comments, this should be a Major priority.

Comment by Ismet Ozalp [ 07/Apr/15 ]

+1000

Comment by Juzer Ali [ 06/Apr/15 ]

+1

Comment by Max Kremer [ 09/Mar/15 ]

+1 This is a major deficiency that needs to be addressed

Comment by Grégoire Aubert [ 18/Feb/15 ]

+1 This feature really needs to be implemented.

Comment by Björn [X] [ 15/Feb/15 ]

+1 I need this to update a document schema (introducing a new default field to all documents)

Comment by Stjepan Buljat [ 12/Feb/15 ]

+1 this is a must have...

Comment by Jason Marmon [ 03/Feb/15 ]

+1 Use case:

I have an array of embedded objects representing customers that we automatically contact. After contacting the customer, we update that embedded document and contact the next one some minutes later. If, however, somehow a second copy of that customer's identifier sneaks into the array, our application contacts this customer over and over until we manually stop it, because only the first copy of the customer's status is updates as 'contacted'.

I agree with the above sentiment - this should already be implemented. It's a bug that needs to be fixed, not an optional new feature.

Comment by Amine [ 21/Jan/15 ]

How is this possible with a NoSQL database document oriented to leak this main feature?
Isn't a document oriented db mainly designed to avoid cross tables/collections queries (that even don't really exists with mognodb...)?
Isn't a document oriented db mainly designed to save multi-level data in a same document?
Is it really a P4?
what an incredible credibility wasting.
(same thing for the $ that only work for the first array level...)

Comment by mickdelaney [ 10/Jan/15 ]

+1 Basically the whole updating array feature is not usable as a result. Its ridiculous.

Comment by Alessandro Giannone [ 10/Jan/15 ]

+1 - Not sure why this is a P4. It's may be a breaking change and may not be trivial, but surely those aren't the factors determining the priority

Comment by mickdelaney [ 17/Nov/14 ]

The lack of support/workarounds on this from the mongodb team is ridiculous.
Updating more than one element in an array is clearly a common requirement.

and yet its been here for years as a minor issue. !!!

Comment by Charles Vallance [ 17/Sep/14 ]

Just wanted to put my +1 here also... found myself trying to write the following:

db.UserViewModels.update({ _id: 112372134004654084 }, { $set: { "DevelopmentData.$.Name": { First: "Charles", Last: "Vallance", PrivacyFirst: "C", PrivacyLast: "Vallance" } } })

Which obviously didn't work.

Comment by Jared Wyatt [ 21/Aug/14 ]

I came across this issue while trying to unset some fields in an array of subdocuments. I'm posting my workaround here, in case anyone else might find it useful.

You can do something similar to the following if (a) you are unsetting fields and know the length of the longest subdoc array, or (b) you are setting fields and all the subdoc arrays are exactly the same length.

var subdoc_array_length = 20;
var unset_fields = {};
for (var i=0; i < subdoc_array_length; i++) {
  unset_fields["subdoc_array." + i + ".field_to_unset"] = "";
}
db.collection.update({ subdoc_array: { $exists: true } }, { $unset: unset_fields }, { multi: true });

If you don't know the subdoc array lengths, you can take the slightly slower boat. The following runs a separate update operation for each document after discovering the subdoc array length.

db.collection.find({ subdoc_array: { $exists: true } }).forEach(function(doc) {
  var unset_fields = {};
  for (var i=0; i < doc.subdoc_array.length; i++) {
    unset_fields["subdoc_array." + i + ".field_to_unset"] = "";
  }
  db.collection.update({ _id: doc._id }, { $unset: unset_fields });
});

Disclaimer: These workarounds are slow. The precise performance depends on the size of your collection, the number of docs you're updating, selection criteria and indexes, etc. Use at your own peril.

Comment by Simon Mansfield [ 20/Aug/14 ]

I too, agree that this is a pretty critical missing feature. For myself to continue using MongoDB I really do think that this, along with a few similar key issues, need to be resolved... Urgently.

Comment by Shahaf Abileah [ 14/Aug/14 ]

+1 I would find this very useful.

My scenario...

I have a bunch of documents, each with an array of items. I'm introducing a new feature that requires a new boolean flag with a default value of true on each item. It would be nice if I could issue a single command to migrate my data, something like this:

db.my_collection.update({}, { $set:

{ 'my_array.*.my_new_field': true }

},

{ multi: true }

)

Instead, it sounds like I'll need to write a script to iterate through all the records and update them "manually". It's doable, but it's more work than it should be. I'm used to being able to do bulk update operations like this in SQL.

Comment by Kevin Wang [X] [ 10/Aug/14 ]

+1, Here is my thoughts to why it is critical and shouldn't be a P4:

This isn't going to be another rant about lack of joins in MongoDB, but as a basis mongo doesn't have joins so it has to really provide a lot of upside to regular RDBMS. In some cases it can for when join's aren't necessary, but for the vast majority of today's applications, joins are a critical piece of functionality that you can't really sidestep. MongoDB has its ways of getting around that though, and currently the best solution to replicate join functionality is to denormalize deep data. Albeit this isn't ideal, but it gets the job done for most cases at the cost of space efficiency. However, complex and deep relationships are extremely common and without this basic querying & updating feature, you can't leverage much of the upside to MongoDB as the lack of this feature forces you to denormalize data that is greater than 1 level deep, regardless of whether you need to reindex that level of data as a separate collection. This significantly challenges the viability of mongodb in a variety of surprisingly common cases. Of course, you can blame the end user for choosing mongo as their db incorrectly, but the reality is that this discretionless usage has driven 10gen to its massive adoption today and supported the high demand for mongo. If the company is to grow and expand to meet the scale of the current hype, it really needs to change its philosophy to cater to how the world uses databases on a fundamental level. We can't jump 10 light years before first building the engine; and I would argue this feature is comparable to inventing the wrench to start screwing the first bolts onto the engine.

Comment by Neville Dipale [ 29/Jul/14 ]
{I know I should post this in the mongo-dev or mongo-user group, but daheck there's already a whole "I need this otherwise I can't use MongoDB" chain here, so I might as well add on :)}

I think one of the things that the MongoDB team should really look into is
enabling users to be able to perform more complex operations such as this
in the server, without a bandwidth round-trip to the application. The
problem of most of today's programmers (myself included) is that we have
the benefit of being able to throw processing powers at problems, instead
of finding more effective ways of performing operations. We rely on
software vendors to (rightly) make our lives easier, and sometimes lack the
ability to roll out some implementations ourselves. I believe that software
vendors should always consider at least creating channels for uses to
create their own 'functions' because the reality is that not every client's
needs will be met without sacrificing usability and performance.

A complex 'query' in my app involves hitting MongoDB thousands of times a
second at worst, which means that if I ever get to 1000 users per second,
my 'replica set' would need to be able to handle >1e6 q/s at worst. I chose
MongoDB due to its relative ease compared to the PostgreSQL 'black box' and
ever-improving geo support, but PostgreSQL being flexible enough to be
programmed to perform complex operations without a bandwidth round-trip
cost still makes it a viable alternative.

I personally don't know what's on the pipeline with MongoDB, but even if
JavaScript/V8 is an issue with server-side scripting (I understand that
indices aren't used, or something along those lines), at least consider
another language, even C++, so that users can be able to roll out update
statements like the one that everyone is complaining about. This would help
reduce the need to implement all sorts of things in the aggregation
framework.

Comment by Dennis Hoefakker [ 29/Jul/14 ]

@Albert Engelbrecht

Yes that was clear to me, as i re-read your comment i read "impossible" :| Because of your sentence "As of now it's impossible to update" (and missing coffee) i was reading "possible" this morning so i thought i missed something.

Sorry for the inconvenience

For me it's totally unclear why this "bug" / "missing feature" is still absent and marked "P4 - Minor", it is a MUST have feature imo.

Is there any methode to "up" this issue ?

Comment by Albert Engelbrecht [ 29/Jul/14 ]

@Denniss Hoefakker

mongo.shell

> db.record.insert({field: [ { name : "Steve" }, { name : "Ron" } ] })
WriteResult({ "nInserted" : 1 })
> db.record.insert({field: [ { name : "Jim" }, { name : "carl" } ] })
WriteResult({ "nInserted" : 1 })
 
> db.record.update({}, { $set : { 'field.name' : "Carl" }}, { multi: true })
WriteResult({
	"nMatched" : 0,
	"nUpserted" : 0,
	"nModified" : 0,
	"writeError" : {
		"code" : 16837,
		"errmsg" : "cannot use the part (field of field.name) to traverse the element ({field: [ { name: \"Steve\" }, { name: \"Ron\" } ]})"
	}
})

So this means that it would be impossible to use the .update() syntax to set a specific field in all arrays in a single operator.

Comment by Dennis Hoefakker [ 29/Jul/14 ]

@Albert Engelbrecht Could you please elaborate how to do that, i'm unable to find it in documentation.

Comment by Henri [ 23/Jul/14 ]

wow totally thought it was a bug in my code _

Comment by Yannick Bétemps [X] [ 17/Jun/14 ]

I think that, on a pure functionnal basis, this issue is closely related to issue n° SERVER-831
Unfortunatelly priority for both tickets is no consistent (MAJOR vs MINOR)
What's the use of embedded arrays update if only the first occurence is updated ? Because most certainly, embedded arrays would very often need several updates at a time.
I'd really love to see this very important feature implemented soon.

Comment by Albert Engelbrecht [ 11/Jun/14 ]

+1

As of now it's impossible to update every element in the array in a single update, instead having to iterate over the array elements and $set them individually.

Comment by Yannick Bétemps [X] [ 10/Jun/14 ]

+1 this definitely IS a basic feature for any database !
Especially document database : since joints are not available there is more data redundancy, hence the multiple update is required to maintain the redundant data up to date (but not only).

Comment by Gabriel Zimmermann [ 05/Jun/14 ]

How come the priority for this is "Minor - P4"???

Comment by Linus Gubenis [ 05/Jun/14 ]

wow, thats something i really thought mongodb is already capable of

+1 $$ implementation! H-)

Comment by Edward [ 27/May/14 ]

+1 for this issue. Please implement this feature.

Comment by Kirtimaan [ 15/May/14 ]

+1 for $$ implementation. Using array_name.$.field_name work on only 1st matched element of array, while my requirement was to update more than 1 element in same record.

Current work around doesn't seem better, given either have to trigger update individually in recursive (making multiple connection / queries) or using save method to update entire array (not an atomic operation).

Comment by Dillon Krug [ 08/May/14 ]

+1 from me too. Hopefully this will be scheduled soon, it's sorely needed.

Comment by ndwiga [ 08/May/14 ]

How many votes does it take for someone to take notice

Comment by Pierre Bazoge [ 06/May/14 ]

+1 ! the power of MongoDB is embedding docs, but if you can't update them in a batch it looses it's value... please schedule this feature asap. BR

Comment by Fergus Nelson [ 06/May/14 ]

Minor? Seriously? I am baffled that this still is not implemented

Comment by Saurabh Soni [ 02/May/14 ]

The wait still continues...!!
Anybody with relatively faster way of all the alternate options of updating records?

Comment by Jose Miguel Díez de la Lastra [ 23/Apr/14 ]

Where is the easy workaround?

Comment by Roman [ 16/Apr/14 ]

This is very expected feature! Please implement it asap!

Comment by Tony Mobily [ 15/Mar/14 ]

If any of the MongoDB developers (or anybody else) feel like helping out, I would love to see if there is indeed a way to deal with my use case...
http://stackoverflow.com/questions/22420712/best-way-to-get-around-bug-1243-in-mongodb-use-positional-operator-to-update-a

Comment by Tony Mobily [ 15/Mar/14 ]

How is this even considered "minor"?
I had no idea this was a problem. I have been scratching my head in front of failing tests that shouldn't fail, and eventually figured out that only one sub-record was being updated.
This is a major issue. It must be possible to update more than one sub-record in one go. What's even worse, is that there is no clear, easy work-around to this. Running the update many times is horrific and possibly immensely expensive. Getting the full array is a joke.
Seriously.

Comment by James Hartig [ 11/Feb/14 ]

Setting a field on all elements is not possible. Throws a "can't append to array using string field name" error.
You also cannot unset from all elements. Filed that separately because the lastErrorObject looks like it actually did: https://jira.mongodb.org/browse/SERVER-12680

Comment by NOVALUE Mitar [ 02/Jan/14 ]

OK. But even setting a field on all elements of an array is not yet possible?

And what I am saying is that I do not understand why there is a need for positional operator when you want to update more than one item in an array (and yes, not necessary all).

Comment by eggtree [ 02/Jan/14 ]

@Mitar
IIUC this issue is not specifically about setting a field on all elements of an array, which can be done as you describe. Again IIUC its more about setting a field on more than one element of an array.

Look at "TEST CASE 2 - UPDATE SPECIFIED ATTRIBUTE OF EACH MATCHED ARRAY ELEMENT FOR EACH MATCHED OBJECT:" in https://jira.mongodb.org/browse/SERVER-1243?focusedCommentId=83185&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-83185 for an example of only the first matching element of an array being updated.

Perhaps a better name for this issue would be "Use positional operator to update more than one item in an array"

Comment by Jake Hoffner [ 11/Dec/13 ]

+1. This is definitely not a minor issue.

Comment by NOVALUE Mitar [ 03/Nov/13 ]

And why using $ at all when updating subdocuments in an array? So based on data from the ticket description, we could just be able to run:

t.update( obj, { $set: {'comments.votes': 1} }, false, true )

and this would set all votes fields of all subdocuments of the comments array. This would allow to use same syntax no matter if you have one subdocument you want to update or multiple in a array. It would mirror selecting documents where you can match fields in a subdocuments in the same way no matter if they are in the array or not.

Comment by Muruga [ 18/Sep/13 ]

I am completely surprised by the fact that this is classified as Minor. It is a must have in any multi-update operations. We are classifying MongoDB as big data and can't kill the performance by doing the same operation multiple times (as an work around). Come on the MongoDB company, please fix this.

After all, we are all supporting MongoDB big time.

Comment by Paul Evans [ 16/Sep/13 ]

+1 Please review this, it's an essential feature, not a minor one! Having to iterate through all items in the document and update it, especially if there's thousands of documents is impractical.

Comment by Alexander Arutuniants [ 13/Sep/13 ]

Need this feature very much! For array of sub documents!

Comment by Scott Lowe [ 08/Aug/13 ]

Am surprised there is no support for this already, would also like to see this scheduled soon.

Comment by Jason Rogers [ 06/Aug/13 ]

Come on 10gen! This is really a useful feature. The current work-around of reading back the documents and updating them individually stinks. What can we do as a community to raise the priority of this feature?

Comment by Michael Henry [ 02/May/13 ]

+1 Would find this very useful.

Comment by josh rothe [ 05/Apr/13 ]

Agree with above- surprised this isn't there, and the workarounds are painful and generally janky. An update would be appreciated.

Comment by Jere Helenius [ 15/Mar/13 ]

Very much needed stuff.

Any update on the status of this?

Comment by Tim S [ 03/Feb/13 ]

Nuts, just plain nuts that we can't update all the items in an array with a single command.

This is fundamental stuff.

Has 10Gen advised why they don't support this yet?

Comment by Bill Walker [ 09/Jan/13 ]

I also need it. I may remove the subdocument array collection into its own collection so that I can accomplish this.

Comment by Nic Cottrell (Personal) [ 08/Jan/13 ]

+1 Still need this.

Comment by James Hartig [ 03/Jan/13 ]

Instead of $$, can we wrap the $set or whatever update operation we want to do in a $each or $all command? Something like:

update({}, {$all: {"my.array": {$set: {"value": 1}}}});

Comment by Michael Arndt [ 12/Dec/12 ]

+1. Need this.

Comment by Andrea Reginato [ 04/Dec/12 ]

+1 Really useful to speed up performances. Please do it.

Comment by Alberto Lopez [ 28/Nov/12 ]

+1. This will really help us. Please implement this feature.

Comment by Elio Capella Sánchez [ 15/Oct/12 ]

+1 very useful, and the workarround is horrible. Please implement this feature.

Comment by Jeremy Martin [ 09/Oct/12 ]

+1 (especially for using a unique positional operator). There are a lot of use cases where a nested array of documents makes sense from a schema perspetive, but the inability to update them all atomically drives schema design in a different direction.

Comment by karthik venkataramani [ 13/Sep/12 ]

This will be really useful to have. +1

Comment by V G [ 06/Sep/12 ]

I can't believe this hasn't been implemented yet. How else does one update multiple objects in an array? Or is this the wrong way to design a schema?

Possible workaround: just run the update command multiple times until all array items have been updated.

Check by find() the original update condition until no more results are returned.

Comment by Jake Orr [ 01/Aug/12 ]

This would be really useful in my current development.

Comment by Shivani [ 11/Jul/12 ]

+1 ... really need this

Comment by Steve Francia [ 05/Jul/12 ]

I'll second (or third) the idea of using a different token to stand for changing (or retrieving) all. Before reading this thread I thought the '%' sign made a lot of sense, but there's a reasonable argument here for the double '$'. All the same, I'd prefer a single character to multiple.

Comment by Mark Dietz [ 10/Jun/12 ]

I like the idea of using $$ for the multiple selector.

I did some digging in the code and found generally where the changes would need to be made, but it was definitely a non-trivial change, so I've let it languish for awhile. I'm starting a new job that every so often has an open source hack day, so we'll see if that helps me get back to it. Haven't had a lot of free time lately and with switching jobs that will probably be using most of my brain power for awhile.

Comment by Dimitris [ 23/May/12 ]

+1 to keep this alive

Comment by Colin Mollenhour [ 14/Feb/12 ]

Just ran into a scenario where I could really benefit from this. In order to prevent breaking backwards compatibility, how about using $$ for mult-updates and $ for single updates. So:

// Current syntax, updates only one embedded doc
db.foo.update({_id:1,"notes.by":"grandma"},{$inc:{"notes.$.priority":1}});
 
// Proposed syntax, updates all matched embedded docs
db.foo.update({_id:1,"notes.by":"grandma"},{$inc:{"notes.$$.priority":1}});

This idea was inspired partially perhaps by Prototype (client-side JS framework) which uses $ for getting single dom elements by id and $$ for getting multiple dom elements by CSS selector.

Comment by Mark Dietz [ 31/Jan/12 ]

Thanks, Eliot.

Regarding $rename:
I wasn't able to find a way with the latest code to do an update with $rename that used the positional operator. I think the below line in update.cpp would prevent this:
uassert( 13487, "$rename source may not be dynamic array", strstr( fieldName , ".$" ) == 0 );

If you meant that after implementing this feature then you'd like $rename to be able to function on a dynamic array as part of this feature, I can keep that in mind while I'm working on it.

Regarding $push:
Below are two test cases for $push to an embedded array. Sorry this is long, but I want to make sure I understand.

I think the other operators would be analogous, unless I'm missing something that makes $push or $pushAll special.

TEST CASE 4 - PUSH TO EACH EMBEDDED ARRAY WHEN MATCH CRITERIA DOES NOT INCLUDE ARRAY
> t.find()

{ "_id": ObjectId("4f2752ecb790d449f2359060"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "add love too" }, { "by": "mom", "text": "stir while adding" } ], 
        "step": "add flour to sugar"
    }, 
    { "notes": [ { "by": "grandma", "text": "add more love" } ], 
      "step": "stir until smooth"
    }, 
    { "notes": [ { "by": "mom", "text": "put down flour first" } ], 
      "step": "roll into circle"
    }
  ], 
  "name": "apple pie"
}

> t.update({}, {$push:{"instructions.$.notes":

{"by":"mark", "text":"love was not enough"}

}}, false, true)
CURRENT RESULT (ERROR WITH MESSAGE BELOW)
can't append to array using string field name [$]
DESIRED RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()

{ "_id": ObjectId("4f2752ecb790d449f2359060"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "add love too" }, { "by": "mom", "text": "stir while adding" }, { "by": "mark", "text":"love was not enough" } } } ], 
      "step": "add flour to sugar"
    }, 
    { "notes": [ { "by": "grandma", "text": "add more love" }, { "by": "mark", "text":"love was not enough" } ], 
      "step": "stir until smooth"
    }, 
    { "notes": [ { "by": "mom", "text": "put down flour first" }, { "by": "mark", "text":"love was not enough" } ]], 
      "step": "roll into circle"
    }
  ], 
  "name": "apple pie"
}

TEST CASE 5 - PUSH TO EMBEDDED ARRAY OF EACH MATCHED ARRAY, BUT NOT UNMATCHED ARRAYS
> t.find()

{ "_id": ObjectId("4f2752ecb790d449f2359060"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "add love too" }, { "by": "mom", "text": "stir while adding" } ], 
        "step": "add flour to sugar"
    }, 
    { "notes": [ { "by": "grandma", "text": "add more love" } ], 
      "step": "stir until smooth"
    }, 
    { "notes": [ { "by": "mom", "text": "put down flour first" } ], 
      "step": "roll into circle"
    }
  ], 
  "name": "apple pie"
}
{ "_id": ObjectId("4f2752f7b790d449f2359061"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "mix in love" } ], 
      "step": "smash bananas"
    }, 
    { "step": "add brown sugar"
    }
  ], 
  "name": "banana bread"
}
{ "_id": ObjectId("4f27530ab790d449f2359062"), 
  "instructions": [
    { "notes": [ { "by": "mom", "text": "easy" } ], 
      "step": "smash apples"
    }
  ], 
  "name": "apple sauce"
}

> t.update(

{"instructions.notes.by":"grandma"}

, {$push:{"instructions.$.notes":

{"by":"mark", "text":"love was not enough"}

}}, false, true)
CURRENT RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()

{ "_id": ObjectId("4f27530ab790d449f2359062"), 
  "instructions": [
    { "notes": [ { "by": "mom", "text": "easy" } ],
      "step": "smash apples"
    }
  ], 
  "name": "apple sauce"
}
{ "_id": ObjectId("4f2752ecb790d449f2359060"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "add love too" }, { "by": "mom", "text": "stir while adding" }, { "by": "mark", "text": "love was not enough" } ], 
      "step": "add flour to sugar"
    }, 
    { "notes": [ { "by": "grandma", "text": "add more love" } ], 
      "step": "stir until smooth"
    }, 
    { "notes": [ { "by": "mom", "text": "put down flour first" } ], 
      "step": "roll into circle"
    }
  ], 
  "name": "apple pie"
}
{ "_id": ObjectId("4f2752f7b790d449f2359061"), 
  "instructions": [
    { "notes": [ {"by": "grandma", "text": "mix in love" }, { "by": "mark", "text": "love was not enough" } ], 
      "step": "smash bananas"
    }, 
    { "step": "add brown sugar" }
  ], 
  "name": "banana bread"
}

DESIRED RESULT (SUCCESS RESULTING IN DATA BELOW)

{ "_id": ObjectId("4f27530ab790d449f2359062"), 
  "instructions": [
    { "notes": [ { "by": "mom", "text": "easy" } ],
      "step": "smash apples"
    }
  ], 
  "name": "apple sauce"
}
{ "_id": ObjectId("4f2752ecb790d449f2359060"), 
  "instructions": [
    { "notes": [ { "by": "grandma", "text": "add love too" }, { "by": "mom", "text": "stir while adding" }, { "by": "mark", "text": "love was not enough" } ], 
      "step": "add flour to sugar"
    }, 
    { "notes": [ { "by": "grandma", "text": "add more love" }, { "by": "mark", "text": "love was not enough" } ], 
      "step": "stir until smooth"
    }, 
    { "notes": [ { "by": "mom", "text": "put down flour first" } ], 
      "step": "roll into circle"
    }
  ], 
  "name": "apple pie"
}
{ "_id": ObjectId("4f2752f7b790d449f2359061"), 
  "instructions": [
    { "notes": [ {"by": "grandma", "text": "mix in love" }, { "by": "mark", "text": "love was not enough" } ], 
      "step": "smash bananas"
    }, 
    { "step": "add brown sugar" }
  ], 
  "name": "banana bread"
}

Comment by Eliot Horowitz (Inactive) [ 30/Jan/12 ]

Need to consider all operators, not just $set.
i.e. could have an embedded array you are doing a $push too or a $rename

This would definitely need to be an option, would break too many existing programs.

Comment by Mark Dietz [ 30/Jan/12 ]

I'm new to MongoDB and thinking about trying to implement this feature. Here's a couple test cases that I think capture the changes for this feature:

TEST CASE 1 - UPDATE SPECIFIED ATTRIBUTE OF EACH ARRAY ELEMENT FOR EACH MATCHED OBJECT:
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "mark", "votes" : 3 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 2 }

,

{ "by" : "jane", "votes" : 8 }

], "title" : "first post" }
> t.update(

{"title":"first post"}

, {$set:{"comments.$.votes":3}}, false, true)
CURRENT RESULT (ERROR WITH MESSAGE BELOW)
can't append to array using string field name [$]
DESIRED RESULT (SUCCESS WITH RESULTING DATA BELOW)
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "mark", "votes" : 3 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 3 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }

TEST CASE 2 - UPDATE SPECIFIED ATTRIBUTE OF EACH MATCHED ARRAY ELEMENT FOR EACH MATCHED OBJECT:
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "mark", "votes" : 3 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 3 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }
> t.update(

{"comments.votes":3}

, {$set:{"comments.$.votes":4}}, false, true)
CURRENT RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "mark", "votes" : 4 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 4 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }
DESIRED RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "mark", "votes" : 4 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 4 }

,

{ "by" : "jane", "votes" : 4 }

], "title" : "first post" }

TEST CASE 3 - UPDATE SPECIFIED ATTRIBUTE OF EACH MATCHED ARRAY ELEMENT FOR EACH MATCHED OBJECT
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "joe", "votes" : 4 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 4 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }
> t.update(

{"comments.by":"joe"}

, {$set:{"comments.$.votes":5}}, false, true)
CURRENT RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "joe", "votes" : 5 }

,

{ "by" : "joe", "votes" : 1 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 5 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }
DESIRED RESULT (SUCCESS RESULTING IN DATA BELOW)
> t.find()
{ "_id" : ObjectId("4f256ec7a23cf8c9e2bce3d3"), "comments" : [

{ "by" : "joe", "votes" : 5 }

,

{ "by" : "joe", "votes" : 5 }

], "title" : "second post" }
{ "_id" : ObjectId("4f2569f7be16970bef9799d9"), "comments" : [

{ "by" : "joe", "votes" : 5 }

,

{ "by" : "jane", "votes" : 3 }

], "title" : "first post" }

Are there other test cases that I should consider?

Some questions for the core contributers:

  • Should this feature be added as an option for the update command or should the existing update command be modified to perform this way?
  • If there is an option, do you have suggestions for the user facing update API?
  • Any tips or warnings on the code where this feature will be implemented? If not, I'll look on my own and we can see what I come up with.
Comment by Claudio Beatrice [ 25/Jan/12 ]

+1

Comment by Joshua Hanson [ 24/Jan/12 ]

+1 workaround for now is something like this (which sucks because it's recursive)

		function convertDirectMessages(id, cb) {
			Conversation.collection.update(
				{'messages.context': 'direct'}, 
				{$set:{'messages.$.context': {type:'direct'}}}, 
				{safe:true, multi:true},
				function(err, updated) {
					if (err) return cb(err);
					if (updated) return convertDirectMessages(id, cb);
					cb();
				}
			);
		}
		convertDirectMessages(posted._id, this);

Comment by František Hába [ 23/Jan/12 ]

+1

Comment by Mikhail Sayapin [ 20/Oct/11 ]

Badly need it for views-by-tags data accumulation.

Comment by Daniel [ 19/Oct/11 ]

+1 It is bad that this has not already been implemented!

Comment by Daniel Perez R [ 11/Oct/11 ]

+1 I also need this.

Comment by maro huang [ 22/Sep/11 ]

This would be very useful, upvoted + 1

Comment by Pekka Mattila [ 30/Aug/11 ]

This would be a very nice feature indeed. Any plans for this?

Comment by Gavin Hogan [ 18/Apr/11 ]

In lieu of a prompt implementation of this I would really appreciate a common work around. Currently I am trying to update an array of embedded documents in a conversation style document where each persons display name is stored with their comment as part of a user summary. If I want to update their first name (for example) I would like to be able to execute this statement.

db.NewsFeed.update( {"comments":{"$elemMatch":

{ "fromUserSummary.id":"4d9f48ffb7e89d85f4e3d913"}

} }, { "$set":

{ "comments.$.fromUserSummary.firstName":"Frankie" }

}, null,

{"multi":1}

)

But this only update the name in the first instance of the comments array. Currently I am planning to recurse this statement until I find no matching instances for the find. Other ideas are appreciated.

Comment by free [ 18/Apr/11 ]

just matched items should be update.

Comment by Martin May [ 09/Apr/11 ]

This would be very useful, upvoted

Comment by Cyril Mougel [ 24/Mar/11 ]

I agree with this feature. It's can be better to have that.

I do a little script to see what happen now if we use the $

https://gist.github.com/885015

Generated at Thu Feb 08 02:56:29 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.