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();
在那个例子中,第一阶段将匹配 j1
和 j2
,因为它们都包含“1234”,然后我想根据任务状态进一步过滤掉作业,例如,只有 j2
的任务有 status==FAILED
,所以我的最终结果就是 j2
文档。
希望如此。我想我可能只需要在最后添加一些巧妙的投影。谢谢
$lookup
管道中的 $match
与 jobCollection
文档无关。它只过滤 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": [] }}},
])
我正在使用 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();
在那个例子中,第一阶段将匹配 j1
和 j2
,因为它们都包含“1234”,然后我想根据任务状态进一步过滤掉作业,例如,只有 j2
的任务有 status==FAILED
,所以我的最终结果就是 j2
文档。
希望如此。我想我可能只需要在最后添加一些巧妙的投影。谢谢
$lookup
管道中的 $match
与 jobCollection
文档无关。它只过滤 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": [] }}},
])