【发布时间】:2021-09-02 15:23:58
【问题描述】:
我刚才问了一个关于在内部数组中对 $lookup 结果进行分组的问题,链接到question
我有一个看起来像这样带有查找结果的数据集
_id: ObjectID('abc'),
sections: [
{
sectionId: "sec0",
sectionName: "ABC",
contents: [
{
contentId: 0,
tasks: [
{
_id: task01
//properties of task01
duration: '2 days',
},
{
_id: task02
//properties of task02
duration: '3 days',
},
],
contentDescription: "Content is etc",
}
]
}
{
sectionId: "sec1",
sectionName: "EFG",
contents: [
{
contentId: 0,
tasks: [
{
_id: task03
//properties of task03
duration: '4 days',
},
{
_id: task04
//properties of task04
duration: '3 days',
},
],
contentDescription: "Content is etc",
}
]
}
]
我使用了以下聚合管道
{
$match: {
_id: id,
},
},
{
$unwind: '$sections',
},
{
$unwind: {
path: '$sections.contents',
preserveNullAndEmptyArrays: true,
},
},
{
$unwind: {
path: '$sections.contents.tasks',
preserveNullAndEmptyArrays: true,
},
},
{
$lookup: {
from: 'tasks',
let: {
task_id: '$sections.contents.tasks.tId',
duration: '$sections.contents.tasks.duration',
},
pipeline: [
{
$match: {
$expr: {
$eq: ['$_id', '$$task_id'],
},
},
},
{
$addFields: {
duration: '$$duration',
},
},
],
as: 'sections.contents.tasks',
},
},
{
$addFields: {
'sections.contents.tasks': {
$arrayElemAt: ['$sections.contents.tasks', 0],
},
},
},
{
$group: {
_id: {
contentId: '$sections.contents.tasks',
sectionId: '$sections.sectionId',
sectionName: '$sections.sectionName',
originalId: '$_id',
},
tasks: {
$push: '$sections.contents.tasks',
},
contentDescription: {
$first: '$sections.contents.contentDescription',
},
},
},
{
$sort: { _id: 1 },
},
{
$group: {
_id: {
sectionId: '$_id.sectionId',
sectionName: '$_id.sectionName',
originalId: '$_id.originalId',
},
contents: {
$push: {
contentId: '$_id.contentId',
tasks: '$tasks',
contentDescription: '$contentDescription',
},
},
},
},
{
$group: {
_id: '$_id.originalId',
sections: {
$push: {
sectionId: '$_id.sectionId',
sectionName: '$_id.sectionName',
contents: '$contents',
},
},
},
},
而且一切正常,但是有一个折痕,假设如果一个人添加了一个部分而不添加其内容,那么以下数据保存在 MongoDB 中
[
{
sectionId: "sec0",
sectionName: "ABC",
contents: [
{
contentId: 0,
tasks: [
{
_id: task01
//properties of task01
duration: '2 days',
},
{
_id: task02
//properties of task02
duration: '3 days',
},
],
contentDescription: "Content is etc",
}
]
}
{
sectionId: "sec1",
sectionName: "EFG",
}
]
对于每个获取请求,我都会得到以下结果(仅发布第二部分元素)
{
sectionId: "sec1",
sectionName: "EFG",
contents: [
{
tasks: [],
contentDescription: null,
}
]
}
因此,客户端正在亮起,因为它无法同时找到 contentDescription 和 tasks,并且由于内容数组的存在,所有检查都失败了。客户端和后端架构都无法进行重构。
如果没有内容数组存在,desired 输出如下所示
_id: ObjectID('abc'),
sections: [
{
sectionId: "sec0",
sectionName: "ABC",
contents: [
{
contentId: 0,
tasks: [
{
_id: task01
//properties of task01
duration: '2 days',
},
{
_id: task02
//properties of task02
duration: '3 days',
},
],
contentDescription: "Content is etc",
}
]
}
{
sectionId: "sec1",
sectionName: "EFG",
}
]
我在聚合管道的最后一个组阶段之后添加了以下阶段,如下所示
{
$addFields: {
'sections.contents.tasks': {
$filter: {
input: '$sections.contents.tasks',
as: 'task',
cond: {
$ne: ['$$task', []],
},
},
},
},
},
但它不起作用,任何建议或帮助将不胜感激。谢谢
【问题讨论】:
-
在展开任务数组时使用
preserveNullAndEmptyArrays: false是否可以避免这种情况? -
这是我做的第一件事,但不幸的是它不起作用,因为 $unwind 不输出任务数组,结果我得到一个空数组。我确信在最后一个 $group 阶段之后的 $project 阶段有某种方法使用 $cond 或任何其他相关聚合查询,以确保如果 contentDescription 为空,并且任务为空,则过滤掉内容数组。我尝试使用 $project 但我被 $cond 难住了
-
这是您要找的吗? mongoplayground.net/p/fQL6Fw8pArk
-
preserveNullAndEmptyArrays: false 如果不存在任务数组则不起作用,这是我的问题的症结
-
@Joe,此外,在您的示例中,聚合管道不会显示没有任何内容数组的部分。
标签: node.js mongodb aggregation-framework