Mongoose 从 2 个集合中查找给出了错误的总和值

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

我有以下收藏

实体:

const Entity = new Schema(
  {
    name: {
      type: String,
      required: true,
    },
    type: {
      type: String,
      required: true,
      enum: ["owner", "customer", "supplier"],
    },

帐号:

const Account = new Schema(
  {
    name: {
      type: String,
      required: true,
    },
    phone: {
      type: String,
      default: "+964",
    },

公关:

const PR = new Schema(
  {
    number: {
      type: Number,
      default: 0,
    },
    customer: {
      type: Schema.Types.ObjectId,
      ref: "Entity",
    },
    owner: {
      type: Schema.Types.ObjectId,
      ref: "Entity",
    },
    account: {
      type: Schema.Types.ObjectId,
      ref: "Account",
    },
    items: [item.schema]
    ,
total_usd: {
  type: Number,
  default: 0,
},
total_iqd: {
  type: Number,
  default: 0,
},

和发票:

const Invoice = new Schema(
  {
    number: {
      type: Number,
      index: true,
      default: 0,
    },
    customer: {
      type: Schema.Types.ObjectId,
      ref: "Entity",
    },
    owner: {
      type: Schema.Types.ObjectId,
      ref: "Entity",
    },
    account: {
      type: Schema.Types.ObjectId,
      ref: "Account",
    },
    total_usd: {
      type: Number,
      default: 0,
    },
    total_iqd: {
      type: Number,
      default: 0,
    },

我需要的是获取按

total_usd
 分组的 
total_iqd
PR
 集合的 
Invoices
status and year and account

总和

我使用以下查询,它会产生非常奇怪的结果和数字

await entityModel
    .aggregate([
      { $match: { _id: new mongoose.Types.ObjectId(req.query._id) } },
      {
        $lookup: {
          from: "invoices",
          localField: "_id",
          foreignField: "customer",
          as: "invoices",
        },
      },

      {
        $unwind: "$invoices",
      },
      {
        $lookup: {
          from: "accounts",
          localField: "invoices.account",
          foreignField: "_id",
          pipeline: [{ $project: { _id: 0, name: 1 } }],
          as: "invoices.account",
        },
      },
      { $unwind: "$invoices.account" },
      {
        $lookup: {
          from: "prs",
          localField: "_id",
          foreignField: "customer",
          as: "prs",
        },
      },
      {
        $unwind: "$prs",
      },
      {
        $lookup: {
          from: "accounts",
          localField: "prs.account",
          foreignField: "_id",
          pipeline: [{ $project: { _id: 0, name: 1 } }],
          as: "prs.account",
        },
      },
      { $unwind: "$prs.account" },
      {
        $group: {
          _id: {
            inv_status: "$invoices.status",
            inv_account: "$invoices.account",
            inv_year: { $year: "$invoices.created_at" },
            pr_status: "$prs.status",
            pr_account: "$prs.account",
            pr_year: { $year: "$prs.created_at" },
          },
          inv_sum_usd: { $sum: "$invoices.total_usd" },
          inv_sum_iqd: { $sum: "$invoices.total_iqd" },
          pr_sum_usd: { $sum: "$prs.total_usd" },
          pr_sum_iqd: { $sum: "$prs.total_iqd" },
        },
      },
    ])
    .then((result) => {
      res.send(result);
    })

结果如下:

[
    {
        "_id": {
            "inv_status": "approved",
            "inv_account": {
                "name": "FIIQ"
            },
            "inv_year": 2023,
            "pr_status": "approved",
            "pr_account": {
                "name": "FIIX"
            },
            "pr_year": 2023
        },
        "inv_sum_usd": 480000,
        "inv_sum_iqd": 0,
        "pr_sum_usd": 514440,
        "pr_sum_iqd": 0
    },
    {
        "_id": {
            "inv_status": "approved",
            "inv_account": {
                "name": "FIIQ"
            },
            "inv_year": 2023,
            "pr_status": "approved",
            "pr_account": {
                "name": "FIIQ"
            },
            "pr_year": 2023
        },
        "inv_sum_usd": 144000,
        "inv_sum_iqd": 0,
        "pr_sum_usd": 40700,
        "pr_sum_iqd": 14256000
    },
    {
        "_id": {
            "inv_status": "approved",
            "inv_account": {
                "name": "FIIX"
            },
            "inv_year": 2023,
            "pr_status": "approved",
            "pr_account": {
                "name": "FIIX"
            },
            "pr_year": 2023
        },
        "inv_sum_usd": 2551740,
        "inv_sum_iqd": 0,
        "pr_sum_usd": 2829420,
        "pr_sum_iqd": 0
    },
    {
        "_id": {
            "inv_status": "approved",
            "inv_account": {
                "name": "FIIX"
            },
            "inv_year": 2023,
            "pr_status": "approved",
            "pr_account": {
                "name": "FIIQ"
            },
            "pr_year": 2023
        },
        "inv_sum_usd": 765522,
        "inv_sum_iqd": 0,
        "pr_sum_usd": 223850,
        "pr_sum_iqd": 78408000
    }
]

这与我的数据不符???!!!(FIIX的total_usd总和= 257220)任何帮助将不胜感激

mongoose mongodb-query aggregation-framework
1个回答
0
投票

问题源于展开后发生的查找。 它像笛卡尔连接一样炸毁了文档的数量。

例如,假设我们有这个文档:

{a: [1,2,3], b: ['x', 'y', 'z']}

放松后

a
,我们得到

{ a: 1, b: ['x',  'y', 'z']}
{ a: 2, b: ['x',  'y', 'z']}
{ a: 3, b: ['x',  'y', 'z']}

然后放松

b
,我们得到

{ a: 1, b: 'x'}
{ a: 1, b: 'y'}
{ a: 1, b: 'z'}
{ a: 2, b: 'x'}
{ a: 2, b: 'y'}
{ a: 2, b: 'z'}
{ a: 3, b: 'x'}
{ a: 3, b: 'y'}
{ a: 3, b: 'z'}

您可以在进行任何展开之前执行查找并压缩查找字段以解决此问题。

await entityModel
  .aggregate([{
      $match: {
        _id: new mongoose.Types.ObjectId(req.query._id)
      }
    },
    {
      $lookup: {
        from: "invoices",
        localField: "_id",
        foreignField: "customer",
        as: "invoices",
        pipeline: [{
            $lookup: {
              from: "accounts",
              localField: "account",
              foreignField: "_id",
              pipeline: [{
                $project: {
                  _id: 1,
                  name: 1
                }
              }],
              as: "account"
            }
          },
          {
            $unwind: "$account"
          },
          { // adds a field to mark the collection we looked up from
            "$addFields": {
              "kind": "invoice"
            }
          }
        ]
      }
    },
    {
      $lookup: {
        from: "prs",
        localField: "_id",
        foreignField: "customer",
        as: "prs",
        pipeline: [{
            $lookup: {
              from: "accounts",
              localField: "account",
              foreignField: "_id",
              pipeline: [{
                $project: {
                  _id: 1,
                  name: 1
                }
              }],
              as: "account"
            }
          },
          {
            $unwind: "$account"
          },
          { // adds a field to mark the collection we lookedup from
            "$addFields": {
              "kind": "pr"
            }
          }
        ]
      }
    },
    {
      $project: {
        _id: 1,
        name: 1,
        type: 1,
        docs: {
          $zip: {
            inputs: [
              "$prs",
              "$invoices"
            ],
            useLongestLength: true
          }
        }
      }
    },
    {
      $unwind: "$docs"
    },
    {
      $unwind: "$docs"
    },
    { // We exclude missing document because we set the `useLongestLength` option when zipping invoices and prs.
      $match: {
        docs: {
          $ne: null
        }
      }
    },
    { // The layout of the results are document wise. It should be possible to layout differently.
      $group: {
        _id: {
          status: "$docs.status",
          account: "$docs.account._id",
          kind: "$docs.kind",
          year: {
            $year: "$docs.created_at"
          }
        },
        sum_usd: {
          $sum: "$docs.total_usd"
        },
        sum_iqd: {
          $sum: "$docs.total_iqd"
        }
      }
    }
  ])

https://mongoplayground.net/p/dPEa2VJUlix

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