1

In one aggregation stage within my MongoDB view pipeline I am using $group. One of the things I'm doing within that $group stage is summing up an openBalance, like this:

  "openBalance": {
    "$sum": "$openBalance"
  },

This works.

However, I also need to get another value, that first matches to a condition, and then sums data. In other words, something like this:

  "customerResponsibleOpenBalance": {
    "$match": {
      "customerResponsible": true
    },
    "$sum": "$openBalance"
  },

However, I can't do this like this within a $group stage, because it results in this error:

customerResponsibleOpenBalance must specify one accumulator.

So how would I go about doing this in a different way? Are $facets my only option here?

Muirik
  • 6,049
  • 7
  • 58
  • 116
  • $group works on a set of documents. Why do you want to use `$match` ? Does it mean "any `customerResponsible` field set to true" ? – mickl Jul 11 '18 at 15:08
  • Yes. That is correct. It means, look through the documents, and if the value for the field`customerResponsible` is set to true, include it in the `$sum` here. – Muirik Jul 11 '18 at 15:09
  • 1
    You can use $sum with $cond expression. Something like `{"$sum":{"$cond":["$customerResponsible","$openBalance",0]}}` and `{"$sum":{"$cond":["$customerResponsible",0, "$openBalance"]}}` – s7vr Jul 11 '18 at 16:09
  • Ah, okay, This looks like the right way to go for what I want to accomplish. – Muirik Jul 11 '18 at 16:10
  • "customerResponsibleOpenBalance": { "$sum": {"$cond":["$customerResponsible","$openBalance", 0] } }, – Muirik Jul 11 '18 at 16:20

1 Answers1

1

$group works on a set of documents so you can only use accumulators to get a result. To get $sum conditionally you can use $cond operator inside of it, and add 0 if there's no match:

{
    $group: {
        _id: null,
        balanceForTrue: { $sum: { $cond: { if: { $eq: [ "$customerResponsible", true ] }, then: "$balance", else: 0  } } },
        balanceForFalse: { $sum: { $cond: { if: { $eq: [ "$customerResponsible", false ] }, then: "$balance", else: 0  } } }
    }
} 
mickl
  • 48,568
  • 9
  • 60
  • 89
  • So, to clarify, I have "openBalance" already. That's working. What I ALSO want is to, on the fly, generate a value for a new field, that sums up the openBalance, just like the first one, but does so ONLY for those documents for which "customerResponsible" is set to true. I also want a third value, giving me the $sum of "openBalance" for where "customerResponsible" is set to false. So, I have openBalance. That's working. Is there a way, within this $group stage, that I could also generate those other two values I need? – Muirik Jul 11 '18 at 16:08
  • Hi mickl can you please let me know why this doesn't work... I am doing `$filter` to 3 nested level... https://mongoplayground.net/p/U_ohSoTZ6Rg... I want only `nokia` element from 3rd array and `6666` from second... If you want then I can ask a question as well... But please help to solve this first – Ashh Jul 13 '18 at 19:46
  • @AnthonyWinzlet I guess you should since it has nothing to do with this question, I'll try to take a look – mickl Jul 13 '18 at 19:51
  • Yes it has nothing with this question but most of the time I see you doing amazing things with aggregation on stack... So for notify you I commented here... Thanks for the help – Ashh Jul 13 '18 at 19:54
  • @AnthonyWinzlet cool, thanks, please open new question and I'll try to fix that, it's hard to explain that in comments – mickl Jul 13 '18 at 20:21