如何在mongo中过滤子数组并返回文档

时间:2018-02-17 07:04:20

标签: mongodb mongodb-query aggregation-framework

我有两个集EmployeeClient

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字段,其中包含ClientIdProjectIdFormId

表单可以在多个客户端中进行多个项目。

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

{
    "_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() 

2 个答案:

答案 0 :(得分: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,所以你必须再次展开$。要筛选出不属于员工的项目,您可以使用$redact来比较两个字段。然后最终得到两级嵌套数组,你应该使用$ group。

答案 1 :(得分:1)

尝试此聚合,我们$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()