Mongodb聚合查找查询-返回所有子文档

时间:2019-05-21 19:20:31

标签: mongodb aggregation-framework lookup

this问题之后,我希望根据相关子文档中的值来过滤父文档列表。

给出以下mongoDB集合。...

    // 'job' collection
    {
      "id"      : j1,
      "mediaID" : "ABC1234"
    },
    {
      "id"      : j2,
      "mediaID" : "DEF1234"
    }

.. and ..

    // 'task' collection

    // j1 tasks
    {
      "id"      : "t1",
      "job"     : "j1",
      "taskName": "MOVE",
      "status"  : "COMPLETE"
    },
    {
      "id"      : "t2",
      "job"     : "j1",
      "taskName": "PUBLISH",
      "status"  : "FAILED"
    },
    // j2 tasks
    {
      "id"      : "t3",
      "job"     : "j2",
      "taskName": "MOVE",
      "status"  : "COMPLETE"
    },
    {
      "id"      : "t4",
      "job"     : "j2",
      "taskName": "PUBLISH",
      "status"  : "COMPLETE"
    }

..其中任务集合通过job.id-> task.job

链接到任务集合

我有一个聚合查询,该查询将根据子集合中的条件过滤job集合。我正在使用Mongo的$lookup的管道语法,并且有类似这样的查询。...

db.getCollection("job").aggregate(
  [
    {

      "$lookup": {
        "from"    : "task",
        "let"     : {
          "job_id": "$_id"
        },
        "pipeline": [
          {
            "$match": {
              "$expr": {
                "$and": [
                  {
                    // link job.id to task.job
                    "$eq": ["$job", "$$job_id"]
                  },
                  {
                    // Filter taskName
                    "$eq": ["$taskName", "PUBLISH"]
                  },
                  {
                    // Filter by status
                    "$eq": ["$status", "FAILED"]
                  }
                ]
              }
            }
          }
        ],
        "as"      : "tasks"
      }
    },
    {
      // Remove ROOT docs that do not meet 'task' criteria
      "$match": {
        "tasks": {"$ne": []}
      }
    }
  ]
);

这很好用,只是我希望结果的父级的所有所有子文档返回到结果中,而不仅仅是匹配的子文档。

例如,上面的查询给了我这个...

  {
     "id"      : j1,
     "mediaID" : "ABC1234"
     "tasks" : [
         {
           "id"      : "t2",
           "job"     : "j1",
           "taskName": "PUBLISH",
           "status"  : "FAILED"
      },
     ]
   },

..但是我想要这个...

  {
     "id"      : j1,
     "mediaID" : "ABC1234"
     "tasks" : [
         {
           "id"      : "t1",
           "job"     : "j1",
           "taskName": "MOVE",
           "status"  : "COMPLETE"
         },
         {
           "id"      : "t2",
           "job"     : "j1",
           "taskName": "PUBLISH",
           "status"  : "FAILED"
      },
     ]
   },

我有墨水,有时需要使用$push,但很困惑!任何帮助表示赞赏。

2 个答案:

答案 0 :(得分:1)

您应该将过滤逻辑移出$lookup,并运行$match作为下一个管道阶段。在那里,您可以使用$anyElementTrue运算符来检查是否存在带有所需值的子文档:

db.job.aggregate([
    {
        $lookup: {
            from: "task",
            localField: "id",
            foreignField: "job",
            as: "tasks"
        }
    },
    {
        $match: {
            $expr: {
                $anyElementTrue: {
                    $map: {
                        input: "$tasks",
                        in: {
                            $and: [
                                { $eq: [ "$$this.taskName", "PUBLISH" ] },
                                { $eq: [ "$$this.status", "FAILED" ] }
                            ]
                        }
                    }
                }
            }
        }
    }
])

免责声明:您的数据/聚合中有两个不同的字段名称:taskNametaskCode。我决定使用第一个。

答案 1 :(得分:0)

您可以使用$ addFields。

db.job.aggregate([
    {$lookup: {from: 'task', localField: 'id', foreignField: 'job', as: 'taskList'}},
    {$addFields: {
      tasks: {
        $filter: {
          input: '$taskList',
          as: 't',
          cond: { $and: [
              {$eq: ['$$t.taskCode', 'PUBLISH']},
              {$eq: ['$$t.status', 'FAILED']}
          ]}
        }
      }
    }},
    {$project: {
      _id: 1,
      mediaID: 1,
      tasks: 1
    }}
])