Uploaded image for project: 'Core Server'
  1. Core Server
  2. SERVER-1243

New operator to update all matching items in an array

    Details

    • Type: New Feature
    • Status: Open
    • Priority: Major - P3
    • Resolution: Unresolved
    • Affects Version/s: None
    • Fix Version/s: Backlog
    • Component/s: Querying, Write Ops
    • Labels:
      None

      Description

      Issue Status as of Aug 19, 2015

      MongoDB appreciates the challenge of maintaining applications utilizing 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 major feature there are serious requirements:

      • a specification for new language features (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) could be considered.
      • must support all existing update modifiers (correctly, and in a non-backwards-breaking way)
        • $rename, $set, $unset, $pull, $push, $bit...
      • must work efficiently with all arrays, including those 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, or improvement, 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.

      Please see this comment below for additional details.

      Original description

      Given the following:

      > var obj = t.findOne()
      { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
        "comments" : [ { "by" : "joe", "votes" : 3 }, { "by" : "jane", "votes" : 7 } ] }
      

      One should be able to modify each item in the comments array by using an update command like the following:

      > t.update( obj, {$set:{'comments.$.votes':1}}, false, true )
      > t.find()
      { "_id" : ObjectId("4b97e62bf1d8c7152c9ccb74"), "title" : "ABC",
        "comments" : [ { "by" : "joe", "votes" : 1 }, { "by" : "jane", "votes" : 1 } ] }
      

        Issue Links

          Activity

          Hide
          mmajidali40 majid ali added a comment -

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

          Show
          mmajidali40 majid ali added a comment - any update on this ticket ? i extremely need it for my project
          Hide
          Arkhee Yannick Bétemps added a comment - - edited

          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)

          Show
          Arkhee Yannick Bétemps added a comment - - edited 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)
          Hide
          asya Asya Kamsky added a comment - - edited

          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

          Show
          asya Asya Kamsky added a comment - - edited 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
          Hide
          adambuczynski Adam Reis added a comment - - edited

          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?

          Show
          adambuczynski Adam Reis added a comment - - edited 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?
          Hide
          asya Asya Kamsky added a comment -

          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.

          Show
          asya Asya Kamsky added a comment - 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 .

            People

            • Votes:
              440 Vote for this issue
              Watchers:
              292 Start watching this issue

              Dates

              • Created:
                Updated: