【问题标题】:How to filter sub array and return document in mongo如何在mongo中过滤子数组并返回文档
【发布时间】:2018-02-17 15:50:19
【问题描述】:

我有两个集合Employee、Client

Employee 架构有以下记录

{
    "_id": ObjectId("5a852dcd0290f7eca89e9a79"),
    "FirstName": "Nirav",
    "LastName": "Modi",
    "Gender": true,
    "Forms": [{
            "ClientId": ObjectId("5a8528ed0290f7eca89e9a5f"),
            "ProjectId": ObjectId("5a856fde0290f7eca89e9a88"),
            "FormId": ObjectId("5a62e561f6647f17f85e54c5")
        }]
}

Client 架构有以下记录

{
    "_id" : ObjectId("5a8528ed0290f7eca89e9a5f"),
    "CompanyName" : "PNB",
    "Projects" : [{
            "_id" : ObjectId("5a856ca70290f7eca89e9a7f"),
            "Name" : "House Loan",
            "Description" : "Get house load",
            "Forms" : []
        }, {
            "_id" : ObjectId("5a856fde0290f7eca89e9a88"),
            "Name" : "Car Loan",
            "Description" : "get car loan",
            "Forms" : [
                ObjectId("5a62e82299d9fe0a14a1ead5"),
                ObjectId("5a6eec263bf43426d4d31780"),
                ObjectId("5a62e561f6647f17f85e54c5")
            ]
        }
    ]
}

在我的系统中,员工被分配了要处理的表单。如您所见,员工架构包含 Forms 字段,其中包含 ClientId、ProjectId、FormId。

表单可以在多个客户端中用于多个项目。

当我获取数据时,我希望输出如下所示

{
    "_id": ObjectId("5a852dcd0290f7eca89e9a79"),
    "FirstName": "Aartik",
    "LastName": "Ladumor",
    "Gender": true,
    "Clients": [{
            "_id": ObjectId("5a8528ed0290f7eca89e9a5f"),
            "CompanyName": "PNB",
            "Projects": [{
                    "_id": ObjectId("5a856fde0290f7eca89e9a88"),
                    "Name": "Car Loan",
                    "Description": "get car loan",
                    "Forms": [
                        ObjectId("5a62e82299d9fe0a14a1ead5"),
                        ObjectId("5a6eec263bf43426d4d31780"),
                        ObjectId("5a62e561f6647f17f85e54c5")
                    ]
                }
            ]
        }
    ]
}

仅获取项目包含分配给员工的表单的客户。

为此我进行如下聚合

db.Employees.aggregate([{
            $lookup: {
                from: "Clients",
                localField: "Forms.ClientId",
                foreignField: "_id",
                as: "Clients"
            }
        }, {
              filter projects array in matched client contains only
              projects that match Employee.Forms each elements 
              ProjectsId -> Client.Projects._id and
              FormId -> in Client.Projects.Forms array containing forms ObjectId 
        }
    ]).pretty() 

【问题讨论】:

    标签: mongodb mongodb-query aggregation-framework


    【解决方案1】:

    你可以试试下面的聚合

    db.employees.aggregate([
      { $unwind: "$Forms" },
      {
        $lookup: {
            from: "clients",
            localField: "Forms.ClientId",
            foreignField: "_id",
            as: "Clients"
        }
      },
      { $unwind: "$Clients" },
      { $unwind: "$Clients.Projects" },
      {
        $redact: {
          $cond: {
            if: { $eq: [ "$Forms.ProjectId", "$Clients.Projects._id" ] },
            then: "$$KEEP",
            else: "$$PRUNE"
          }
        } 
      },
      {
        $group: {
          _id: {
            _id: "$_id",
            ClientId: "$Clients._id"
          },
          FirstName: { $first: "$FirstName" },
          LastName: { $first: "$LastName" },
          Gender: { $first: "$Gender" },
          Client: { $first: "$Clients" },
          Projects: { $push: "$Clients.Projects" }
        }
      },
      {
        $group: {
          _id: "$_id._id",
          FirstName: { $first: "$FirstName" },
          LastName: { $first: "$LastName" },
          Gender: { $first: "$Gender" },
          Clients: { $push: {
            _id: "$Client._id",
            CompanyName: "$Client.CompanyName",
            Projects: "$Projects"
          } }
        }
      }
    ])
    

    基本上你必须多次使用$unwind,因为你需要比较值而不是数组。所以 $lookup 合并了两个集合。然后你需要比较项目ID,所以你必须再次$unwind。要过滤掉不属于员工的项目,您可以使用$redact 比较两个字段。然后以两级嵌套数组结束,您应该使用 $group。

    【讨论】:

    • 它工作正常。让我检查更多数据。如果它可以工作,那么将标记为答案。
    【解决方案2】:

    试试这个聚合,我们$lookup来自员工集合的客户ID,然后$filter来自匹配客户的项目和表单ID

    db.Employee.aggregate(
        [
            {$lookup : {
                from : "Client",
                localField : "Forms.ClientId",
                foreignField : "_id",
                as : "Clients"
            }},
            {$addFields : {
                "Clients.Projects" : {
                    $filter : {
                    input : {$arrayElemAt : ["$Clients.Projects", 0]},
                    as : "project", 
                    cond : {$and : [
                        {$eq : [{$arrayElemAt : ["$Forms.ProjectId", 0]}, "$$project._id"]},
                        {$in : [{$arrayElemAt : ["$Forms.FormId", 0]}, "$$project.Forms"]}
                    ]}}
                }
            }}
        ]
    ).pretty()
    

    【讨论】:

      猜你喜欢
      • 2015-03-13
      • 2022-07-06
      • 2019-04-23
      • 2021-03-20
      • 1970-01-01
      • 2018-01-07
      • 2023-04-05
      • 2021-09-18
      • 1970-01-01
      相关资源
      最近更新 更多