【问题标题】:MongoDB get $lookup leftoversMongoDB 得到 $lookup 剩菜
【发布时间】:2021-03-22 19:51:36
【问题描述】:

我正在尝试实现一个将两个集合合并为一个的查询,这可以使用$lookup 来完成。我想要实现的是,如果localFieldforeignField 不匹配,我希望也包含该记录。这是可能的还是我错过了什么?以下是我迄今为止尝试过的基本$lookup 聚合:

const billPayments = await BillPayment.aggregate([
      {
        $match: {
          isActive: true,
        },
      },
      {
        $lookup: {
          from: PackageList.collection.name,
          localField: "serviceNumber",
          foreignField: "serviceNumber",
          as: "package",
        },
      },
      { $unwind: "$package" },
      {
        $project: {
          serviceNumber: 1,
          amount: 1,
          isCaution: 1,
          paymentDate: 1,
          remark: 1,
          package: "$package",
          id: "$_id",
        },
      },
    ]);
res.json(billPayments);

billPayments 的当前结果仅适用于两个集合中存在serviceNumber 的那些BillPayment 数据。但我希望将PackageList 中不存在的那些记录也包括在内。我怎样才能做到这一点?

我很确定我在这里遗漏了一些东西。任何帮助表示赞赏。

#编辑预期输出

"billPayments": [
    {
        "amount": 299.25,
        "id": "604f5bbd6bf57e1f9c58203f",
        "isActive": true,
        "isCaution": false,
        "packageService": {
          "_id": "5fc4a5e15ce5bf227451f4b8",
          "isActive": true,
          "serviceType": "Post_Paid",
          "moneyLimit": 3000
        },
        "employee": {
          // Employee data from Employee collection to be included
        }
        "paymentDate": "2021-03-14T21:00:00.000Z",
        "remark": "",
        "serviceNumber": "0935998681"
      },
      {
        "amount": 299.25,
        "id": "604f5bbd6bf57e1f9c58203f",
        "isActive": true,
        "packageService": {
            //   If there is no match for serviceNumber
        },
        "paymentDate": "2021-03-14T21:00:00.000Z",
        "remark": "",
        "serviceNumber": "0735448621"
      }
  ]

编辑其他$lookup 查询:

我有第二级$lookup 可以从另一个集合中获取更多信息。如下所示:

{
    $lookup: {
      from: PackageList.collection.name,
      localField: "serviceNumber",
      foreignField: "serviceNumber",
      as: "package",
    },
  },
  { $unwind: "$package" },
  {
    $lookup: {
      from: Employee.collection.name,
      localField: "package.employee",
      foreignField: "_id",
      as: "employee",
    },
  },

正如@DheemanthBhat 在他的回答中所建议的那样,我尝试从Package 中删除unwind,并且可以轻松获得一个空列表。但是,如果我尝试在Package 上使用$lookup 来获取员工信息,则会抛出MongoError,因为它无法查找空对象。

有没有什么方法可以从第二级$lookup 跳过那些empty 包?或者在这种情况下如何使用$ifNull 来跳过空结果中的$unwind

【问题讨论】:

  • 为什么不直接将 $merge 合并到其中一个集合中?
  • @Yahya 你能告诉我怎么做吗?我对 mongoDb 很陌生
  • 如果你给我看示例文件,我应该可以整理一些东西
  • @Kirubel 还包括预期的输出。
  • @DheemanthBhat 我已经用预期的示例输出编辑了我的问题

标签: mongodb mongoose mongodb-query


【解决方案1】:

因此,当您在没有$unwind 的情况下执行$lookup 时,与PackageList 集合匹配或不匹配的BillPayment 集合中的所有详细信息都将可用。如果您$unwind,那么带有空packageService 的文档将被删除。根据您的预期输出如果您想要一个空的 packageService 对象,请检查以下查询。

注意:请在使用以下代码之前验证集合/模型名称和字段名称。

const billPayments = await BillPayment.aggregate([
  {
    $match: { isActive: true }
  },
  {
    $lookup: {
      from: "PackageList",
      localField: "serviceNumber",
      foreignField: "serviceNumber",
      as: "packageService"
    }
  },
  {
    $project: {
      serviceNumber: 1,
      amount: 1,
      isCaution: 1,
      paymentDate: 1,
      remark: 1,
      package: "$package",
      id: "$_id",
      packageService: {
        $ifNull: [{ $arrayElemAt: ["$packageService", 0] }, {}]
      }
    }
  }
]);

输出:

/* 1 createdAt:3/15/2021, 6:36:05 PM*/
{
    "_id" : ObjectId("604f5bbd6bf57e1f9c58203f"),
    "isCaution" : false,
    "amount" : 299.25,
    "paymentDate" : ISODate("2021-03-15T02:30:00.000+05:30"),
    "serviceNumber" : "0935998681",
    "id" : ObjectId("604f5bbd6bf57e1f9c58203f"),
    "packageService" : {
        "_id" : ObjectId("5fc4a5e15ce5bf227451f4b8"),
        "serviceNumber" : "0935998681",
        "isActive" : true,
        "serviceType" : "Post_Paid",
        "moneyLimit" : 3000
    }
},

/* 2 createdAt:3/15/2021, 6:36:05 PM*/
{
    "_id" : ObjectId("604f5bbd6bf57e1f9c582040"),
    "isCaution" : false,
    "amount" : 300,
    "paymentDate" : ISODate("2021-03-16T02:30:00.000+05:30"),
    "serviceNumber" : "0735448621",
    "id" : ObjectId("604f5bbd6bf57e1f9c582040"),
    "packageService" : {
        
    }
}

测试数据:

BillPayment收藏

{
    "_id" : ObjectId("604f5bbd6bf57e1f9c58203f"),
    "isActive" : true,
    "isCaution" : false,
    "amount" : 299.25,
    "paymentDate" : ISODate("2021-03-15T02:30:00.000+05:30"),
    "serviceNumber" : "0935998681"
},
{
    "_id" : ObjectId("604f5bbd6bf57e1f9c582040"),
    "isActive" : true,
    "isCaution" : false,
    "amount" : 300,
    "paymentDate" : ISODate("2021-03-16T02:30:00.000+05:30"),
    "serviceNumber" : "0735448621"
}

PackageList收藏

{
    "_id" : ObjectId("5fc4a5e15ce5bf227451f4b8"),
    "serviceNumber" : "0935998681",
    "isActive" : true,
    "serviceType" : "Post_Paid",
    "moneyLimit" : 3000
}

【讨论】:

  • 我不知道为什么,但它说 MongoError 在我这边
  • 我想通了,错误正在发生,因为我对一个空对象有第二个$lookup 查询。有没有办法在第二个$lookup 查询之前使用$ifNull
  • 是的。如果您尝试更新问题,我可以提供帮助。
  • 我也尝试使用preserveNullAndEmptyArrays: false 来包含空包,但无法跳过$lookup 查询。
  • 嘿,我非常努力地重现了您的问题,但是对于我们使用的 $lookup 样式,我没有收到任何错误。
猜你喜欢
  • 2018-01-10
  • 1970-01-01
  • 2022-01-05
  • 1970-01-01
  • 1970-01-01
  • 2017-08-30
  • 2021-02-12
  • 1970-01-01
  • 2019-05-12
相关资源
最近更新 更多