如何根据MongoDB中的条件投射子文档中字段的和?

hwamh0ep  于 2022-12-22  发布在  Go
关注(0)|答案(1)|浏览(99)

我有一个包含以下文档的客户集合:

{
  "_id": 1,
  firstname: "John",
  lastname: "Doe",
  credits: [
    {
      cDate: "2020-01-16",
      cAmount: 350
    },
    {
      cDate: "2021-02-07",
      cAmount: 180
    },
    {
      cDate: "2021-06-25",
      cAmount: 650
    },
  ]
}
{
  "_id": 2,
  firstname: "Bob",
  lastname: "Smith",
  credits: [
    {
      cDate: "2020-03-19",
      cAmount: 200
    },
    {
      cDate: "2020-08-20",
      cAmount: 90
    },
    {
      cDate: "2021-11-11",
      cAmount: 300
    },
  ]
}

现在我想返回特定年份(即2021年)的总支出。
数据应如下所示:

{"firstname": "John", "lastname": "Doe", "total": 830},
{"firstname": "Bob", "lastname": "Smith", "total": 300}

首先,我尝试匹配预期年份(2021)内包含cDates的记录,以减少记录数量(实际数据集有数百个客户),然后投影所需字段:

Customer.aggregate([
  {
    $match: {
      credits: {
        $elemMatch: {
          cDate: {
            $gte: ISODate("2021-01-01"),
            $lte: ISODate("2021-12-31"),
          },
        },
      },
    },
  },
  {
    $project: {      
      _id: 0,
      firstname: 1,
      lastname: 1,
      total: {
        $sum: "$credits.cAmount",
      },
    },
  }
])

结果是:

{"firstname": "John", "lastname": "Doe", "total": 1180},
{"firstname": "Bob", "lastname": "Smith", "total": 590}

差不多了,现在我想跳过不包含预期年份(2021)的信用记录,这样就只计算cDate等于2021的值。
$match保持不变,我尝试在$project位中添加一个$cond

Customer.aggregate([
  {
    $match: {
      credits: {
        $elemMatch: {
          cDate: {
            $gte: ISODate("2021-01-01"),
            $lte: ISODate("2021-12-31"),
          },
        },
      },
    },
  },
  {
    $project: {      
      _id: 0,
      firstname: 1,
      lastname: 1,
      total: {        
        $cond: {
          if: { credits: { cDate: { regex: "2021-" } } }, // if cDate contains 2021-
          then: { $sum: "$credits.cAmount" },             // add the cAmount
          else: { $sum: 0 }                               // else add 0
        },
      },
    },
  }
])

这个结果仍然是一样的,所有的总数都是从所有年份计算出来的。

{"firstname": "John", "lastname": "Doe", "total": 1180},
{"firstname": "Bob", "lastname": "Smith", "total": 590}

我错过了什么?
谢谢你的帮助。

egdjgwm8

egdjgwm81#

属性cDate有字符串值,不能按日期类型匹配。

  • $matchcDate乘以$regex并匹配"2021"
  • $reduce迭代credits数组的循环,将初始值设置为0
  • $substr以从0索引和4个字符(年份)中获取cDate的子字符串
  • $cond检查子串是否为"2021",然后$sum初始值为cAmount,否则返回初始值
Customer.aggregate([
  {
    $match: {
      "credits.cDate": {
        $regex: "2021"
      }
    }
  },
  {
    $project: {
      _id: 0,
      firstname: 1,
      lastname: 1,
      total: {
        $reduce: {
          input: "$credits",
          initialValue: 0,
          in: {
            $cond: [
              {
                $eq: [
                  { $substr: ["$$this.cDate", 0, 4] },
                  "2021"
                ]
              },
              { $sum: ["$$value", "$$this.cAmount"] },
              "$$value"
            ]
          }
        }
      }
    }
  }
])

Playground

相关问题