Uploaded image for project: 'Documentation'
  1. Documentation
  2. DOCS-16193

[SERVER] Mention non-guaranteed order of $accumulator

      The $accumulator operator lets you define a custom accumulator using Javascript: https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/accumulator/

      Part of the contract between the user and the server is that the server is free to decide the order and grouping when it calls init()/accumulate()/merge(), and so the user is responsible for making sure these functions are insensitive to order and grouping.

      We do allude to this, because we document the conditions when merge() is called: https://www.mongodb.com/docs/v6.0/reference/operator/aggregation/accumulator/#merge-two-states-with--merge. But maybe we should be more explicit about the assumptions the server makes about the user's init()/accumulate()/merge() functions.

      For example, here's an example of a bad, grouping-sensitive $accumulator:

      {$accumulator: {
         init: function () {return "a";},
         accumulate: function(state, arg) {return state + arg;},
         accumulateArgs: ["b"],
         merge: function(state1, state2) {return state1 + state2;}
         lang: "js"
      }}
      

      This accumulator is bad because it gives you a different answer depending on how the server chooses to do the grouping:

      // It can group this way:
      accumulate(accumulate(init(), "b"), "b") = ("a" + "b") + "b" = "abb"
      
      // or this way instead:
      merge(init(), accumulate(accumulate(init(), "b"), "b")) = "a" + (("a" + "b") + "b") = "aabb"
      

      If you think something precise would be useful, I think this captures it:

      // merge() is associative and commutative
      merge(state1, merge(state2, state3)) == merge(merge(state1, state2), state3)
      merge(state1, state2) == merge(state2, state1)
      
      // init() is an identity
      merge(init(), state) == state
      merge(state, init()) == state
      
      // accumulate() and merge() are related
      accumulate(state, value) == merge(state, accumulate(init(), value))
      

            Assignee:
            jeffrey.allen@mongodb.com Jeffrey Allen
            Reporter:
            david.percy@mongodb.com David Percy
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved:
              4 weeks, 2 days ago