MongoDB:有没有一种方法可以计算过去记录的总和?

时间:2020-04-05 01:35:44

标签: mongodb mongodb-query aggregation-framework

假设我有一个像这样的数据集:

yearMonth | amount
201908    | 100
201909    | 100
201910    | 200
201911    | 100
201912    | 200
202001    | 300
202002    | 200

有没有一种方法可以对通过记录进行求和/累加以获得类似这样的结果集:

yearMonth | amount | balance
201908    | 100    | 100
201909    | 100    | 200
201910    | 200    | 400
201911    | 100    | 500
201912    | 200    | 700
202001    | 300    | 1000
202002    | 200    | 1200

2 个答案:

答案 0 :(得分:0)

尝试以下聚合查询:

db.collection.aggregate([
   /** Sort on entire collection is not preferred, but you need it if 'yearMonth' field is not ordered */
  /** Group on empty & push all docs to 'data' array */
  { $group: { _id: "", data: { $push: "$$ROOT" } } },
  {
    $project: {
      data: {
        $let: {
          vars: {
            data: {
              $reduce: {
                input: "$data", /** Iterate over 'data' array & push newly formed docs to docs array */
                initialValue: { amount: 0, docs: [] },
                in: {
                    docs: {
                    $concatArrays: [
                      "$$value.docs",
                      [
                        {
                          _id: "$$this._id",
                          yearMonth: "$$this.yearMonth",
                          amount: "$$this.amount",
                          balance: {
                            $add: ["$$value.amount", "$$this.amount"],
                          },
                        },
                      ],
                    ],
                  },
                  amount: { $add: ["$$value.amount", "$$this.amount"] },
                },
              },
            },
          },
          in: "$$data.docs", /** Return only 'docs' array & ignore 'amount' field */
        },
      },
    },
  },
  /** unwind 'data' array(newly formed 'data' array field) */
  {
    $unwind: "$data",
  },
  /** Replace data object as new root for each document in collection  */
  {
    $replaceRoot: {
      newRoot: "$data",
    },
  },
]);

测试: MongoDB-Playground 参考: aggregation-pipeline-operators

答案 1 :(得分:0)

在此mapReduce的指导下使用answer收集方法,您可以获得所需的结果。

这是使用以下选项的pymongo解决方案:

  1. map函数-这将对要发出的键,值对(yearMonth和Amount)进行初始映射。
  2. 减少功能-在这种情况下无需采取任何措施。
  3. out-指定将输出放置在何处-可以是集合,或者在这种情况下仅是内联处理。
  4. scope-指定滚动总计字段-称为total
  5. 完成-进行实际总计。

这是python(pymongo)代码:

from pymongo import MongoClient
from bson.code import Code

client = MongoClient()
db = client.tst1
coll = db.mapr1

map1 = Code('''
        function () {
            emit(
                this.yearMonth, 
                this.amount              
                ); 
            }
    ''')

reduce1 = Code('''
    function (key, values) {
        return value;
               }
               ''')

fin1 = Code('''
            function(key, value) {
                total += value;
                return {amount: value, balance: total};
            }
''')

result = coll.map_reduce(map1, reduce1, out={'inline': 1}, scope={'total': 0}, finalize=fin1)

for doc in result['results']:
    print(f'The doc is {doc}')

结果:

The doc is {'_id': 201908.0, 'value': {'amount': 100.0, 'balance': 100.0}}
The doc is {'_id': 201909.0, 'value': {'amount': 100.0, 'balance': 200.0}}
The doc is {'_id': 201910.0, 'value': {'amount': 200.0, 'balance': 400.0}}
The doc is {'_id': 201911.0, 'value': {'amount': 100.0, 'balance': 500.0}}
The doc is {'_id': 201912.0, 'value': {'amount': 200.0, 'balance': 700.0}}
The doc is {'_id': 202001.0, 'value': {'amount': 300.0, 'balance': 1000.0}}
The doc is {'_id': 202002.0, 'value': {'amount': 200.0, 'balance': 1200.0}}

收藏中的文件

{'_id': ObjectId('5e89c410b187b1e1abb089af'),
 'amount': 100,
 'yearMonth': 201908}
{'_id': ObjectId('5e89c410b187b1e1abb089b0'),
 'amount': 100,
 'yearMonth': 201909}
{'_id': ObjectId('5e89c410b187b1e1abb089b1'),
 'amount': 200,
 'yearMonth': 201910}
{'_id': ObjectId('5e89c410b187b1e1abb089b2'),
 'amount': 100,
 'yearMonth': 201911}
{'_id': ObjectId('5e89c410b187b1e1abb089b3'),
 'amount': 200,
 'yearMonth': 201912}
{'_id': ObjectId('5e89c410b187b1e1abb089b4'),
 'amount': 300,
 'yearMonth': 202001}
{'_id': ObjectId('5e89c410b187b1e1abb089b5'),
 'amount': 200,
 'yearMonth': 202002}