使用嵌套查询的Mongo $lookup过滤器

3
我正在使用mongoDB的$lookup函数,特别是管道语法进行尝试,以便我能够执行一些比我使用的ORM(Sails/Waterline)更复杂的查询操作。
我的数据简化版本如下:...
    // 'job' collection
    {
      "id"      : j1,
      "mediaID" : "ABC1234"
    },
    {
      "id"      : j2,
      "mediaID" : "DEF1234"
    },
    {
      "id"      : j3,
      "mediaID" : "FGH3456"
    }

..and..

    // 'task' collection

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

..其中任务集合通过job.id -> task.job链接到作业集合。

我想要实现的是能够通过job.mediaID和/或task.status进行作业筛选。目前我的查询几乎可以得到我想要的结果,但它无法过滤jobs,只是没有填充tasks部分。

我目前的查询如下...

    let results = await jobCollection.aggregate([

      // First filter jobs with matching criteria
      {
        $match: {
          $text: {$search: "1234"}
        }
      },

      // Next, link the task collection, and filter by status
      {
        "$lookup": {
          from    : 'task',
          'let'   : {job_id: '$_id'},
          pipeline: [
            {
              $match: {
                $expr: {
                  $and: [
                    // This does the linking of job.id -> task.job_id
                    {$eq: ['$job', '$$job_id']},
                    // This filters out unwanted tasks
                    {$eq: ['$status', 'FAILED']}
                  ]
                }
              }
            }
          ],
          as      : 'tasks'
        }
      }
    ])
    .toArray();

在这个例子中,第一个阶段将匹配j1j2,因为它们都包含 "1234",然后我希望进一步根据任务状态过滤作业,例如,只有j2有一个任务的status==FAILED,所以我的最终结果将只是j2文档。
我希望这样就清楚了。我认为我只需要在最后添加一些聪明的投影。谢谢。
1个回答

3

$lookup管道内的$matchjobCollection文档无关,它仅过滤tasks集合中的文档。因此,在$lookup之后,您必须再使用一个$match阶段来过滤出ROOT(jobCollection)文档。

jobCollection.aggregate([
  { "$match": { "$text": { "$search": "1234" }}},
  { "$lookup": {
    "from": "task",
    "let": { "job_id": "$_id" },
    "pipeline": [
      { "$match": {
        "$expr": {
          "$and": [
            { "$eq": ["$job", "$$job_id"] },
            { "$eq": ["$status", "FAILED"] }
          ]
        }
      }}
    ],
    "as": "tasks"
  }},
  { "$match": { "tasks": { "$ne": [] }}},
])

1
谢谢,我知道这一定是我错过的简单东西。仍在努力理解它们。 - dandanknight
有没有想过如何在输出时同时保留所有子文档,而不仅仅是匹配的一个? - dandanknight

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接