【问题标题】:Using $sum and $cond to get $sum of values, not sum of instances in mongo [duplicate]使用 $sum 和 $cond 获取 $sum 值,而不是 mongo 中的实例总和 [重复]
【发布时间】:2018-12-19 22:28:54
【问题描述】:

我正在尝试结合使用 $group 和 $project 运算符(除非有更好的选择)来生成两个值。

考虑如下所示的文档数据结构:

[
  {
    _id: 1,
    openBalance: 22,
    customerResponsible: true
  },
  {
    _id: 2,
    openBalance: 16,
    customerResponsible: false
  },
  {
    _id: 3,
    openBalance: 10,
    customerResponsible: true
  },
  {
    _id: 4,
    openBalance: 20,
    customerResponsible: false
  },
]

我要做的是输出一个值为customerOpenBalance 的文档,它代表“customerResponsible”为true 的文档的总openBalance。还有一个值agencyOpenBalance,它表示“customerResponsible”设置为false的总openBalance。

现在,我可以在$group 阶段做到这一点:

"customerResponsibleOpenBalance" : { "$sum" : { "$cond" : [ "$customerResponsibile", 1, 0 ] }},

然后在稍后的$project 阶段执行此操作:

"customerResponsibleOpenBalance" : { "$sum": "$customerResponsibleOpenBalance" }

但这给我的是instances 中的$sum,而不是我真正想要的,即openBalance 中的 的总和,其中,对于customerResponsibleOpenBalance 的情况,我定位的布尔值 customerResponsibletrue

如何调整此聚合以获取在$openBalance 中找到的值的$sum,而不是实例的$sum

我的完整聚合管道如下所示(关键阶段是第 6 阶段的 $group 和第 18 阶段的 $project:

db.transactions.aggregate(

  // Pipeline
  [
    // Stage 1
    {
      $match: {
        "openBalance": {
          "$ne": 0.0
        }
      }
    },

    // Stage 2
    {
      $lookup: {
        "from": "customers",
        "localField": "customer.id",
        "foreignField": "_id",
        "as": "customer"
      }
    },

    // Stage 3
    {
      $unwind: {
        "path": "$customer"
      }
    },

    // Stage 4
    {
      $lookup: {
        "from": "visits",
        "localField": "visit.id",
        "foreignField": "_id",
        "as": "visit"
      }
    },

    // Stage 5
    {
      $unwind: {
        "path": "$visit"
      }
    },

    // Stage 6
    {
      $group: {
        "_id": "$customer._id",
        "submissions": {
          "$push": "$submissions"
        },
        "staffMember": {
          "$first": "$staffMember.id"
        },
        "visit": {
          "$first": "$visit"
        },
        "openBalance": {
          "$sum": "$openBalance"
        },
        "customerResponsibleOpenBalance": {
          "$sum": {
            "$cond": ["$visit.customerResponsibility", 1, 0]
          }
        },
        "agencyResponsibleOpenBalance": {
          "$sum": {
            "$cond": ["$visit.customerResponsibility", 0, 1]
          }
        },
        "openClaims": {
          "$sum": {
            "$cond": {
              "if": {
                "$gt": ["$submissions.0.responses.balance", 0.0]
              },
              "then": 1.0,
              "else": 0.0
            }
          }
        }
      }
    },

    // Stage 7
    {
      $addFields: {
        "payerInfo": "$submissions.0.details.agency._id"
      }
    },

    // Stage 8
    {
      $lookup: {
        "from": "agencies",
        "localField": "submissions.0.details.agency._id",
        "foreignField": "_id",
        "as": "agency"
      }
    },

    // Stage 9
    {
      $unwind: {
        "path": "$agency"
      }
    },

    // Stage 10
    {
      $addFields: {
        "claimSupervisor": "$agency.claims.supervisor"
      }
    },

    // Stage 11
    {
      $lookup: {
        "from": "staffmembers",
        "localField": "claimSupervisor",
        "foreignField": "_id",
        "as": "claimSupervisor"
      }
    },

    // Stage 12
    {
      $unwind: {
        "path": "$claimSupervisor"
      }
    },

    // Stage 13
    {
      $lookup: {
        "from": "customers",
        "localField": "_id",
        "foreignField": "_id",
        "as": "customer"
      }
    },

    // Stage 14
    {
      $unwind: {
        "path": "$customer"
      }
    },

    // Stage 15
    {
      $lookup: {
        "from": "locales",
        "localField": "customer.locale",
        "foreignField": "_id",
        "as": "locale"
      }
    },

    // Stage 16
    {
      $unwind: {
        "path": "$locale"
      }
    },

    // Stage 17
    {
      $lookup: {
        "from": "agencies",
        "localField": "agencies",
        "foreignField": "_id",
        "as": "agencies"
      }
    },

    // Stage 18
    {
      $project: {
        "customer": {
          "_id": 1.0,
          "name": 1.0
        },
        "agency": {
          "_id": 1.0,
          "name": 1.0,
          "transactionType": 1.0
        },
        "visit": {
          "_id": 1.0,
          "customerResponsibility": 1.0
        },
        "openBalance": 1.0,
        "openClaims": 1.0,
        "customerResponsibleOpenBalance": {
          "$sum": "$customerResponsibleOpenBalance"
        },
        "agencyResponsibleOpenBalance": {
          "$sum": "$agencyResponsibleOpenBalance"
        },
        "locale": {
          "_id": 1.0,
          "name": 1.0
        },
        "firstSubmission": {
          "$arrayElemAt": ["$submissions", 0.0]
        },
        "lastSubmission": {
          "$arrayElemAt": ["$submissions", -1.0]
        },
        "claimSupervisor": {
          "_id": 1.0,
          "name": 1.0
        }
      }
    },

    // Stage 19
    {
      $unwind: {
        "path": "$firstSubmission"
      }
    },

    // Stage 20
    {
      $unwind: {
        "path": "$lastSubmission"
      }
    },

    // Stage 21
    {
      $project: {
        "firstSubmission": {
          "details": 0.0,
          "responses": 0.0
        },
        "lastSubmission": {
          "details": 0.0,
          "responses": 0.0
        }
      }
    },
  ],

);

【问题讨论】:

  • 我有一种感觉,有一大堆事情不太对劲。如果您可以发布一些具有所需输出的匹配示例数据,我相信我们可以为您提供正确的结果。

标签: javascript mongodb aggregation-framework


【解决方案1】:

对不起,我最初被您的示例数据误导了一点。现在,有了已编辑的问题和完整的管道,我认为您只需要更改即可

"customerResponsibleOpenBalance" : { "$sum" : { "$cond" : [ "$customerResponsibile", 1, 0 ] }}

"customerResponsibleOpenBalance" : { "$sum" : { "$cond" : [ "$customerResponsibile", "$openBalance", 0 ] }},

【讨论】:

  • 当 customerResponsible 为 true 时,我会得到一个值,但当 customerResponsible 为 false 时,我还需要一个值。我该怎么做?
  • 两次错误。 ;) 请查看更新的答案,解释这里发生了什么。
  • 是的。请参阅此处的示例:docs.mongodb.com/manual/reference/operator/aggregation/group。另请参阅我的更新答案。
  • 啊,所以你可以将一个数组传递给$cond。我没有意识到这一点。
  • 只需交换 ifelse 位:"customerResponsibleOpenBalance" : { "$sum" : { "$cond" : [ "$customerResponsibile" : 0, "$openBalance" ] }}
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2019-11-17
  • 2018-09-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-05-21
相关资源
最近更新 更多