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

Mongo $lookup filter using nested query

我正在使用 mongoDB 的 $lookup 函数,特别是管道语法,以允许我执行一些比我使用的 ORM (Sails/Waterline) 允许的更复杂的查询。

我的数据的简化版本看起来像....

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

..和..

    // '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 and/or 和 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 文档。

希望如此。我想我可能只需要在最后添加一些巧妙的投影。谢谢

$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": [] }}},
])