Aggregate documents by a Rounded value Key

2019-07-11 08:12发布

问题:

Example docs

[
  {
    value: 207.9
  }, 
  {
    value: 208.1
  },
  {
    value: 202.1
  },
  {
    value: 201.9
  }
]

How could you use MongoDB's aggregation framework to group documents into clusters that are within a numerical range of each other? How would you split the example documents into two seperate groups, with one group containing the documents with values 207.9 and 208.1 and another group containing the documents with the values 202.1 and 201.9?

I am not sure what the _id would be since the grouping is not a static value. The expected output would look like something like

[
  {
    _id: ?
    avg: 208,
    count: 2
  },
  {
    _id: ?
    avg: 202,
    count: 2
  }
]

回答1:

You can, but it depends on the decimal point precision as to how you implement the math.

For instance for single point precision, multiply by 10:

db.items.aggregate([
  { "$group": {
    "_id": {
      "$add": [
          { "$subtract": [
              "$value",
              { "$mod": [ "$value", 1 ] }
          ]},
          { "$cond": [
              { "$lt": [
                  { "$mod": [ 
                      { "$multiply": [ "$value", 10 ] },
                      10 
                  ]},
                  5
              ]},
              0,
              1
          ]}
       ]
    },
    "count": { "$sum": 1 }
  }}
])                 

The $mod and $multiply operations convert the first decimal to a number between 1 and 10. If that value is less than 5 then return 0 otherwise 1, to then be added to the rounded floor of the original number.

Which gives results:

{ "_id" : 202, "count" : 2 }
{ "_id" : 208, "count" : 2 }

Just factor the numbers by 10 to change the precision in the results.

Or do it shorter if you don't care at all about precision:

db.items.aggregate([
  { "$group": {
    "_id": {
      "$add": [
          { "$subtract": [
              "$value",
              { "$mod": [ "$value", 1 ] }
          ]},
          { "$cond": [
              { "$lt": [
                  { "$mod": [ "$value", 1 ] },
                  0.5
              ]},
              0,
              1
          ]}
       ]
    },
    "count": { "$sum": 1 }
  }}
])