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

Allow logical operators on non-top-level expressions in $pull operations

    • Type: Icon: Improvement Improvement
    • Resolution: Won't Do
    • Priority: Icon: Minor - P4 Minor - P4
    • None
    • Affects Version/s: None
    • Component/s: Write Ops
    • None
    • Query
    • None
    • 0
    • None
    • None
    • None
    • None
    • None
    • None

      It would be desirable to allow logical operators over non-top-level expressions in $pull operations. Currently, the following is an error, and there is no equivalent way to express it in one update:

      db.foo.update({}, {$pull: {a: {$or: [{$lt: 1}, {$gt: 10}]}}})
      

      Original description:
      At present it is only possible to present exact conditions to the $pull operaor. Take the following document:

          {
              foo: {
                  bar: [1, 2, 3, 3, 4, 5, 5]
             }
          }
      

      Now let's say I want to $unset the first occurence of 5 in the array, so the you could do:

          db.collection.update({ "foo.bar": 5 },{ "$unset": { "foo.bar.$": 1 } })
      

      Which is all fine as now the first of the values for 5 is null:

          {
              foo: {
                  bar: [1, 2, 3, 3, 4, null, 5]
             }
          }
      

      But now if you want to remove both "null" and values "less than" 4 you need to perform several updates:

          db.collection.update({ },{ "$pull": { "foo.bar": { "$lt": 4 } } })
          db.collection.update({ },{ "$pull": { "foo.bar": null } })
      

      So the current syntax to $pull seems to consider that the immediate "key" identifier inside the $pull operation needs to be the identifier for the array from which the items would be pulled from.

      It would be nicer if full query conditions could be set such as:

          db.collection.update(
              { },
              { "$pull": { 
                  "$or": [
                     { "foo.bar": { "$lt": 4 },
                     { "foo.bar": null }
                 ]
             }}
      

      But there is of course an ambiguity on "which field" is set for the array within an $or condition. That does not error presently, but of course does not work either.

      A possible alternate syntax could be:

          db.collection.update(
              { },
              { "$pull": { "foo.bar": { "$in": [{ "$lt": 4 },null] }} }
          )
      

      Being a shorter version of $or via $in, but of course that does error due to $in not allowing such a contruct for evaluation.

      On the other hand using $pullAll does not error here:

          db.collection.update(
              { },
              { "$pullAll": { "foo.bar": [{ "$lt": 4 },null ] }}
          )
      

      But of course only removes "null" values and ignores the conditional statement as a literal.

      There must be some way to work the syntax in for multiple conditions without performing multiple update operations. Even the first $or example would be fine if there were some check to make sure you were not operating a condition on a different document element within the $pull operation, so that both elements had to be "foo.bar" in this case.

      Allowing this but producing an error where the field conditions did not match would seem a valid approach.

            Assignee:
            backlog-server-query Backlog - Query Team (Inactive)
            Reporter:
            blakes1971 Blakes Seven
            Votes:
            1 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: