如何按日期对项目列表求和

问题描述 投票:0回答:1

我使用 MongoDB 版本 7。我存储付款数据以及订单和买家信息。我在一个包含订单和买家信息的集合中有一些付款,我按订单 ID 将其分组到下一个 JSON 结果:

{
    "incomeCash": [
        {
            "_id": "64d5fe21fb5b6271ce7934a1",
            "buyer": {
                "title": "buyer1",
                "key": "64234a2711d053037a0362d1"
            },
            "key": "64d5fe21fb5b6271ce7934a1", //order 1 key
            "title": "ORDER 1",
            "payments": [
                {
                    "date": "2023-07-15T00:00:00.000Z",
                    "amount": "1.01"
                }
            ],
            "total": "1.01",
            "direction": "in"
        },
        {
            "_id": "6451db5cd001097cb1f27651",
            "buyer": {
                "title": "buyer1",
                "key": "64234a2711d053037a0362d1"
            },
            "key": "6451db5cd001097cb1f27651", //order 2 key
            "title": "ORDER 2",
            "payments": [
                {
                    "date": "2023-05-08T00:00:00.000Z",
                    "amount": "1.01"
                },
                {
                    "date": "2023-05-18T00:00:00.000Z",
                    "amount": "2.02"
                },
                {
                    "date": "2023-07-15T00:00:00.000Z",
                    "amount": "3.03"
                }
            ],
            "total": "6.06",
            "direction": "in"
        }
    ]
}

所以我的问题是如何按

buyer.key
按日期汇总付款的所有订单进行分组,我要获取下一个 JSON 样式:

[
    {
        "_id": "64234a2711d053037a0362d1",
        "key": "64234a2711d053037a0362d1", //buyer key
        "title": "buyer 1",
        "subLevels": [
            {
                "key": "64d5fe21fb5b6271ce7934a1", //order 1 key
                "title": "ORDER 1",
                "payments": [
                    {
                        "date": "2023-07-15T00:00:00.000Z",
                        "amount": "1.01"
                    }
                ],
                "total": "1.01",
                "direction": "in"
            },
            {
                "key": "6451db5cd001097cb1f27651", //order 2 key
                "title": "ORDER 2",
                "payments": [
                    {
                        "date": "2023-05-08T00:00:00.000Z",
                        "amount": "1.01"
                    },
                    {
                        "date": "2023-05-18T00:00:00.000Z",
                        "amount": "2.02"
                    },
                    {
                        "date": "2023-07-15T00:00:00.000Z",
                        "amount": "3.03"
                    }
                ],
                "total": "6.06",
                "direction": "in"
            }
        ],
        "total": 7.07,
        "payments": [
            {
                "date": "2023-05-08T00:00:00.000Z",
                "amount": "1.01"
            },
            {
                "date": "2023-05-18T00:00:00.000Z",
                "amount": "2.02"
            },
            {
                "date": "2023-07-15T00:00:00.000Z", //group by date
                "amount": "4.04" //sum by date
            }
        ]
    }
]

附注所有金额和总计均为十进制类型,目前我尝试将

$group
$accumulator
和函数一起使用,但并非所有金额都正确求和,例如:

{
  "date": "2023-05-08T00:00:00.000Z",
  "amount": "1.01"
},
{
  "date": "2023-05-18T00:00:00.000Z",
  "amount": "2.02"
},
{
  "date": "2023-07-15T00:00:00.000Z",
  "amount": "NumberDecimal(\"1.01\")NumberDecimal(\"3.03\")"
}

也许还有另一种按日期支付金额的变体,没有函数和带有累加器的组?

mongodb aggregation-framework aggregation
1个回答
1
投票

认为这是一个复杂的查询,需要多次展开和分组文档。

  1. $unwind
    - 将
    payments
    数组解构为多个文档。

  2. $group
    - 按
    buyer.key
    payments.date
    分组以执行求和。并将原始文件保留在
    root
    字段中。

  3. unwind
    - 将
    root
    数组解构为多个文档。

  4. $group
    - 按
    root._id
    分组,以便输出文档应与原始文档类似。

  5. $group
    - 按
    buyer.key
    分组。

  6. $set
    - 按
    subLevels
    字段对
    payments
    date
    数组中的元素进行排序。特殊情况是在排序之前需要额外的步骤从
    payments
    数组中删除重复元素。

db.incomeCash.aggregate([
  {
    $unwind: "$payments"
  },
  {
    $group: {
      _id: {
        buyerKey: "$buyer.key",
        date: {
          $toDate: "$payments.date"
        }
      },
      amount: {
        $sum: {
          $toDecimal: "$payments.amount"
        }
      },
      root: {
        $push: "$$ROOT"
      }
    }
  },
  {
    $unwind: "$root"
  },
  {
    $group: {
      _id: "$root._id",
      buyer: {
        $first: "$root.buyer"
      },
      key: {
        $first: "$root.key"
      },
      title: {
        $first: "$root.title"
      },
      payments: {
        $push: "$root.payments"
      },
      sumPayments: {
        $addToSet: {
          date: "$_id.date",
          amount: "$amount"
        }
      },
      total: {
        $first: "$root.total"
      },
      direction: {
        $first: "$root.direction"
      }
    }
  },
  {
    $group: {
      _id: "$buyer.key",
      title: {
        $first: "$buyer.title"
      },
      subLevels: {
        $addToSet: {
          key: "$key",
          title: "$title",
          payments: "$payments",
          total: "$total",
          direction: "$direction"
        }
      },
      total: {
        $sum: {
          $toDecimal: "$total"
        }
      },
      payments: {
        $push: "$sumPayments"
      }
    }
  },
  {
    $set: {
      subLevels: {
        $sortArray: {
          input: "$subLevels",
          sortBy: {
            "payment.date": 1
          }
        }
      },
      payments: {
        $sortArray: {
          input: {
            $reduce: {
              input: "$payments",
              initialValue: [],
              in: {
                $let: {
                  vars: {
                    elem: {
                      $concatArrays: [
                        "$$this",
                        "$$value"
                      ]
                    }
                  },
                  in: {
                    $setUnion: "$$elem"
                  }
                }
              }
            }
          },
          sortBy: {
            date: 1
          }
        }
      }
    }
  }
])

演示@Mongo Playground

© www.soinside.com 2019 - 2024. All rights reserved.