【问题标题】:$projection & $sum not working as expected in MongoDB aggregation$projection 和 $sum 在 MongoDB 聚合中没有按预期工作
【发布时间】:2020-02-18 21:17:27
【问题描述】:

这里是所有细节。

注意:我只提到必需的示例字段

集合 1:订单

{
    "_id": ObjectId("5e3eb2846cfe9912ece77732"),
    "isApproved": NO,
    "orderCreatedforDate": ISODate("2020-02-15T18:30:00Z"),
    "vendorOrder": [
      {
        "_id": ObjectId("5e3cfb1f3f6d3816a4410d97"),
        "publicationName": "Times of India",
        "productCode": "TCE1",
        "tradeCopies": 40
      },
      {
        "_id": ObjectId("5e3cfb1f3f6d3816a4410d96"),
        "publicationName": "Economic Times",
        "productCode": "ECE1",
        "tradeCopies": 21
      }
    ],
    "frequency": "SA",
    "vendorId": ObjectId("5e3d05ba964d0e06c4bb0f07"),
    "dealerId": ObjectId("5e1d82156a67173cb877f67d"),

}

此集合中有多个文档,但我们需要明天日期的文档,即:"orderCreatedforDate" : ISODate("2020-02-14T18:30:00Z"),并且可以有其他文档具有不同的 vendorId 或 DealerId

集合 2:出版物

{
    "_id": ObjectId("5e1efac668c3c811c83263cc"),
    "publicationName": "Times Of India",
    "productCode": "ECE1",
    "frequency": "SA",
    "city": "Chennai",
    "coverPrice": 4,

  },
  {
    "_id": ObjectId("5e1efac668c3c811c83263cc"),
    "publicationName": "Times Of India",
    "productCode": "TCE1",
    "frequency": "SA",
    "city": "Chennai",
    "coverPrice": 5.5,

}

这是示例文档之一,还有其他频率不同的文档,例如“MO”、“TU”等...以及不同的城市。 我需要明天的文件,即“SA”和城市Chennai,以便我可以获取(coverPrice + productCode + city)

集合 3:边距

{
    "_id": ObjectId("5e4281e7fec2e01a4c60b406"),
    "dealerId": ObjectId("5e1d82156a67173cb877f67d"),
    "vendorId": ObjectId("5e3d05ba964d0e06c4bb0f07"),
    "productCode": "ECE1",
    "frequency": "SA",
    "discount": 0,

  },
  {
    "_id": ObjectId("5e4281e7fec2e01a4c60b406"),
    "dealerId": ObjectId("5e1d82156a67173cb877f67d"),
    "vendorId": ObjectId("5e3d05ba964d0e06c4bb0f07"),
    "productCode": "TCE1",
    "frequency": "SA",
    "discount": 26,

}

保证金收取中的“折扣”以 %age 为单位 [例如,“折扣”:26 为 26%]。

现在折扣取决于 [productCode、vendorId 和城市]如果我有一个不同 "vendorId":ObjectId("5e3d05ba964d0e06c4cc007b") 的订单,我需要考虑这个供应商的折扣。 p>

这是迄今为止我通过此查询能够实现的目标

db.orders.aggregate([
  {
    "$match": {
      "dealerId": ObjectId("5e1d82156a67173cb877f67d"),
      "vendorId": ObjectId("5e3d05ba964d0e06c4bb0f07"),
      "orderCreatedforDate": ISODate("2020-02-15T18:30:00Z"),

    }
  },
  {
    "$unwind": {
      "path": "$vendorOrder"
    }
  },
  {
    $replaceRoot: {
      newRoot: "$vendorOrder"
    }
  },
  {
    $lookup: {
      from: "publications",
      let: {
        productCode: "$productCode"
      },
      pipeline: [
        {
          $match: {
            frequency: "SA",
            $expr: {
              $eq: [
                "$productCode",
                "$$productCode"
              ]
            }
          }
        }
      ],
      as: "publications"
    }
  },
  {
    "$unwind": "$publications"
  },
  {
    $lookup: {
      from: "margins",
      let: {
        productCode: "$productCode"
      },
      pipeline: [
        {
          $match: {
            frequency: "SA",
            $expr: {
              $eq: [
                "$productCode",
                "$$productCode"
              ]
            }
          }
        }
      ],
      as: "margins"
    }
  },
  {
    "$unwind": "$margins"
  },
  {
    "$group": {
      "_id": {
        "productCode": "$productCode",
        "date": "$orderCreatedforDate",
        "coverPrice": "$publications.coverPrice",
        "discount": "$margins.discount",
        "tradeCopies": "$tradeCopies",
        "dealerId": "$orders.dealerId"
      },
      "tradeCopies": {
        "$sum": "$tradeCopies"
      }
    }
  },
  {
    "$project": {
      "dealerId": "$vendorOrder.dealerId",
      "tradeCopies": 1,
      "billOfTheDay": {
        "$multiply": [
          "$tradeCopies",
          {
            "$subtract": [
              "$_id.coverPrice",
              {
                "$multiply": [
                  "$_id.coverPrice",
                  {
                    "$divide": [
                      "$_id.discount",
                      100
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      "totalBill": {
        "$sum": [
          "billOfTheDay"
        ]
      }
    }
  }
])

这个查询的输出是:

{
    "_id": {
      "productCode": "ECE1",
      "coverPrice": 4,
      "discount": 0,
      "tradeCopies": 67
    },
    "tradeCopies": 67,
    "billOfTheDay": 268,
    "totalBill": 0
  },
  {
    "_id": {
      "productCode": "TCE1",
      "coverPrice": 4,
      "discount": 38,
      "tradeCopies": 30
    },
    "tradeCopies": 30,
    "billOfTheDay": 74.4,
    "totalBill": 0
}

我已经能够获得单个贸易副本的账单,这可以在我的输出 TCE1 的每日账单:74.4 和 ECE1 的每日账单:268 中看到。

我想要他们的总数,即 [TCE1+ECE1 : 74.4,268],但这个查询似乎并不好。现在我想在计算完所有 tradeCopies 的 [productCode,coverPrice,discount(vendorIddependent)] 后达到总金额 另一个问题是计算未完成的:

集合 4:付款

{

     "date" : ISODate("2020-02-15T18:30:00Z"),
     "dealerId" : ObjectId("5e1d82156a67173cb877f67d"),
     "vendorId" : ObjectId("5e3d05ba964d0e06c4bb0f07"),
     "receivables" : 120,
},
{

     "date" : ISODate("2020-02-13T18:30:00Z"),
     "dealerId" : ObjectId("5e1d82156a67173cb877f67d"),
     "vendorId" : ObjectId("5e3d05ba964d0e06c4bb0f07"),
     "receivables" : 110,
}

我需要计算应收账款总额,然后需要计算未偿付。

这是预期的输出

invoice: {
    vendorId: ObjectId("5e3d05ba964d0e06c4bb0f07"),
    dealerId: ObjectId("5e1d82156a67173cb877f67d"),
    billOfTheDay:"342.4"
    recievables: "120"   //latest amount received for the day
    outstanding:"112.4   //"total receivable - bill of the day
}

此外,是否可以将所有这些保存在新集合中以供付款历史参考,我想将这些字段保存到 paymenthistory 集合中

{
    productCode,
    vendorId,
    dealerId,
    receivables,
    effectivePrice:(tradeCopies*(coverPrice-(coverPrice*discount%))),
    date, 
    billOfTheDay, 
    totalBillOfTheday
}

如果这不能保存到一个新的集合中,至少我可以计算出未完成的

【问题讨论】:

    标签: mongodb aggregation-framework


    【解决方案1】:

    我已经能够获得单个贸易副本的账单,这可以在我的输出 TCE1 的每日账单:74.4 和 ECE1 的每日账单:268 中看到。我想要他们的总数,即 [TCE1+ECE1 : 74.4,268],但这个查询似乎并不好。

    您可以通过向管道添加额外的 $group 阶段来实现此目的。如果您按null 分组,$group 阶段会计算所有输入文档作为一个整体的累积值。

    {
        $group: {
            _id: null,
            totalBill: {
                $sum: "$billOfTheDay"
            }
        }
    }
    

    所以现在您的管道将如下所示:

    [{$unwind: {
      path: '$vendorOrder'
    }}, {$replaceRoot: {
      newRoot: '$vendorOrder'
    }}, {$lookup: {
      from: 'publications',
      'let': {
        productCode: '$productCode'
      },
      pipeline: [
        {
          $match: {
            frequency: 'SA',
            $expr: {
              $eq: [
                '$productCode',
                '$$productCode'
              ]
            }
          }
        }
      ],
      as: 'publications'
    }}, {$unwind: '$publications'}, {$lookup: {
      from: 'margins',
      'let': {
        productCode: '$productCode'
      },
      pipeline: [
        {
          $match: {
            frequency: 'SA',
            $expr: {
              $eq: [
                '$productCode',
                '$$productCode'
              ]
            }
          }
        }
      ],
      as: 'margins'
    }}, {$unwind: '$margins'}, {$group: {
      _id: {
        productCode: '$productCode',
        date: '$orderCreatedforDate',
        coverPrice: '$publications.coverPrice',
        discount: '$margins.discount',
        tradeCopies: '$tradeCopies',
        dealerId: '$orders.dealerId'
      },
      tradeCopies: {
        $sum: '$tradeCopies'
      }
    }}, {$project: {
      dealerId: '$vendorOrder.dealerId',
      tradeCopies: 1,
      billOfTheDay: {
        $multiply: [
          '$tradeCopies',
          {
            $subtract: [
              '$_id.coverPrice',
              {
                $multiply: [
                  '$_id.coverPrice',
                  {
                    $divide: [
                      '$_id.discount',
                      100
                    ]
                  }
                ]
              }
            ]
          }
        ]
      },
      totalBill: {
        $sum: [
          'billOfTheDay'
        ]
      }
    }}, {$group: {
      _id: null,
            totalBill: {
                $sum: "$billOfTheDay"
            }
    }}]
    

    此外,是否可以将所有这些保存在新集合中以供付款历史参考,我想将这些字段保存到 paymenthistory 集合中

    是的,您可以使用 $out 获取聚合管道的结果并将它们保存到集合中。 https://docs.mongodb.com/manual/reference/operator/aggregation/out/index.html

    我没有在您最初的问题中关注您的其他问题。如果您仍有疑问,请添加更多详细信息并再次提问。

    【讨论】:

    • 我尝试在投影之前、投影之后添加额外的 $group 舞台,但它不起作用,是的,你是对的,我尝试了 bot $out 和 $merge,但它们正在保存 $projection stage 返回的任何内容而且我无法获得新集合的所有必填字段,而且 $out 只是在我运行查询时替换值但我想保存记录而不是 $merge 只是继续创建新文档,你能编辑我的查询吗虽然我的方法是将当天的总账单保存在新集合中而不是计算未完成的,但要计算总账单和未清余额
    • 我更新了上面的答案,表明 $group 阶段应该在管道的末尾进行。
    • "我尝试了 bot $out 和 $merge,但它们正在保存 $projection 阶段返回的任何内容,我无法获取新集合的所有必填字段" 是的,您需要包括您希望在管道的每个阶段的最终输出中包含的任何字段。查看docs.mongodb.com/manual/reference/operator/aggregation/out/… 以确定 $out 或 $merge 是否更适合您的用例。
    • @-Lauren 感谢您后来的建议,我能够获得 totalBill 但除了 totalBill 之外没有任何东西被预测,因此没有任何东西被保存在新集合中。
    • Gald 你能够让 totalBill 工作!您需要更新管道的每个阶段,以包含您想要传递到下一个阶段的数据。
    猜你喜欢
    • 2020-03-15
    • 2018-12-31
    • 2021-03-10
    • 2022-01-04
    • 2020-05-31
    • 1970-01-01
    • 1970-01-01
    • 2021-07-12
    • 1970-01-01
    相关资源
    最近更新 更多