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

Aggregation accumulators does not allow the new "direct" array notation

    • Type: Icon: Bug Bug
    • Resolution: Duplicate
    • Priority: Icon: Major - P3 Major - P3
    • None
    • Affects Version/s: 3.2.5
    • Component/s: Aggregation Framework
    • None
    • Query
    • ALL
    • Hide

      Insert some data

          db.test.insert({ "a": 1, "b": 2 })
      

      Use the array expression notation to result in an array of arrays after $push

          db.test.aggregate([
             { "$group": {
                 "_id": null,
                 "data": { "$push": ["$a","$b"] }
             }}
         ])
      

      Produces an error, but $project and other operators allow it

          db.test.aggregate([
             { "$project": {
                 "data": ["$a","$b"]
             }}
         ])
      

      But not accumulators of any kind;

          db.test.aggregate([
             { "$group": {
                 "_id": null,
                 "data": { "$first": ["$a","$b"] }
             }}
         ])
      

      This produces the same error due to the argument being in array notation:

      "aggregating group operators are unary"

      So in order to get an "array" you still need $map:

          db.test.aggregate([
             { "$group": {
                 "_id": null,
                 "data": { 
                   "$first": {
                     "$map": {
                       "input": ["A","B"],
                       "as": "el",
                       "in": {
                         "$cond": [
                           { "$eq": [ "$$el", "A" ] },
                           "$a",
                           "$b"
                         ]
                      }
                   }
                 }
             }}
         ])
      

      Which yields an array in response, but since it is not directly notated as such the expression is allowed.

      Desired output from $push

          { "_id": null, "data": [[1,2]] }
      
      Show
      Insert some data db.test.insert({ "a" : 1, "b" : 2 }) Use the array expression notation to result in an array of arrays after $push db.test.aggregate([ { "$group" : { "_id" : null , "data" : { "$push" : [ "$a" , "$b" ] } }} ]) Produces an error, but $project and other operators allow it db.test.aggregate([ { "$project" : { "data" : [ "$a" , "$b" ] }} ]) But not accumulators of any kind; db.test.aggregate([ { "$group" : { "_id" : null , "data" : { "$first" : [ "$a" , "$b" ] } }} ]) This produces the same error due to the argument being in array notation: "aggregating group operators are unary" So in order to get an "array" you still need $map: db.test.aggregate([ { "$group" : { "_id" : null , "data" : { "$first" : { "$map" : { "input" : [ "A" , "B" ], "as" : "el" , " in " : { "$cond" : [ { "$eq" : [ "$$el" , "A" ] }, "$a" , "$b" ] } } } }} ]) Which yields an array in response, but since it is not directly notated as such the expression is allowed. Desired output from $push { "_id" : null , "data" : [[1,2]] }

      MongoDB 3.2 allows direct notation of arrays as an expression, and is usually fine in most constructs. ie.

      
          db.test.aggregate([
             { "$project": {
                 "data": ["$a","$b"]
             }}
         ])
      
      

      However, when you attempt this notation as an argument to $push you get an error:

      
          db.test.aggregate([
             { "$group": {
                 "_id": null,
                 "data": { "$push": ["$a","$b"] }
             }}
         ])
      
      

      So the case still requires transposition of elements using $map as an argument to $push in order to get the desired result:

      
          db.test.aggregate([
             { "$group": {
                 "_id": null,
                 "data": { 
                   "$push": {
                     "$map": {
                       "input": ["A","B"],
                       "as": "el",
                       "in": {
                         "$cond": [
                           { "$eq": [ "$$el", "A" ] },
                           "$a",
                           "$b"
                         ]
                      }
                   }
                 }
             }}
         ])
      
      

      Where $push is actually happy that the expression can be evaluated, even though the returned element is an array.

      Though the error itself is self explanatory and there are cases where this would avert undesired output, it is not really consistent with the usage in other constructs.

      It might therefore be desirable to just allow the array expression to be applied, but then only possibly error for things like $sum, or maybe even in that case just produce the 0 return value.

      So overall unsure if it is best to error in such a case or just produce what may be unexpected results if the usage was not intended that way. For cases where the intended result was indeed array content to be sent to the accumulator, then there is an inconsistency with usage in other places.

            Assignee:
            backlog-server-query Backlog - Query Team (Inactive)
            Reporter:
            neillunn Neil Lunn
            Votes:
            0 Vote for this issue
            Watchers:
            8 Start watching this issue

              Created:
              Updated:
              Resolved: