Node.js Mongoose虚拟填充和聚合
我尝试在使用较新的虚拟填充功能(使用Mongoose4.13、Mongo3.6)的Mongoose模式上进行聚合 假设我有以下模式(为便于说明而简化): 使用.populate()查询项目并填充相关任务工作正常,如:Node.js Mongoose虚拟填充和聚合,node.js,mongodb,mongoose,mongoose-populate,Node.js,Mongodb,Mongoose,Mongoose Populate,我尝试在使用较新的虚拟填充功能(使用Mongoose4.13、Mongo3.6)的Mongoose模式上进行聚合 假设我有以下模式(为便于说明而简化): 使用.populate()查询项目并填充相关任务工作正常,如: Project.find({projectId:}).populate('tasks'); 但现在我想按项目总结任务的小时数(顺便说一句,将$sum部分保留在下面)。不管怎样,我只会得到空数组。是否可以使用虚拟填充或进行聚合 const result = await Projec
Project.find({projectId:}).populate('tasks');
但现在我想按项目总结任务的小时数(顺便说一句,将$sum部分保留在下面)。不管怎样,我只会得到空数组。是否可以使用虚拟填充或进行聚合
const result = await Project.aggregate([
{ $match : { projectId: <id> } },
{ $lookup: {
from: 'tasks',
localField: 'projectId',
foreignField: 'projectId',
as: 'tasks'
},
{
$unwind: '$tasks'
}
}
]);
const result=wait Project.aggregate([
{$match:{projectId:}},
{$lookup:{
来自:“任务”,
localField:'projectd',
foreignField:“projectId”,
作为:“任务”
},
{
$unwind:“$tasks”
}
}
]);
虚拟填充不适用于聚合,因为“返回的文档是纯javascript对象,而不是mongoose文档(因为可以返回任何形状的文档)。”(c),文档中的更多信息-参考mongoose的文档:
参数不会强制转换到模型的模式,因为$project运算符允许在管道的任何阶段重新定义文档的“形状”,这可能导致文档的格式不兼容
本质上,这意味着当使用聚合时,mongoose允许通过使用模式实现的任何功能都不会被应用。事实上,您需要直接参考MongoDB的文档(特别是)
产出如下:
[{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: [{
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 2,
__v: 0
},
{
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 1,
__v: 0
}
]
}]
但你可能会问:“这基本上就是我所拥有的,为什么这样做有效?!”
我不确定您的示例代码是否被复制/粘贴,但在提供的示例中,$unwind
阶段似乎意外包含在管道的第二阶段($lookup
)。如果要将其添加为第三阶段,如下面的代码所示,那么输出将被更改,如图所示
return Project.aggregate([
{ $match: { projectId: 1 }},
{
$lookup: {
from: 'tasks',
localField: 'projectId',
foreignField: 'projectId',
as: 'tasks'
}
},
{ $unwind: '$tasks' }
]).exec();
产出:
[{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: {
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 1,
__v: 0
}
},
{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: {
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 2,
__v: 0
}
}
]
mongoose>=3.6支持该方法 因此,您可以像这样将聚合方法的
结果
传递给populate方法
var opts=[{path:'tasks'}];
const populatedResult=等待项目。填充(结果,选项);
Hmm。。我在这里提到了对虚拟填充使用$lookup。有什么想法吗?谢谢,非常感谢。我发现了我的问题。我在模式上使用自定义的集合名称,使集合更易于区分。$lookup聚合中的“from”字段指定集合名称,我试图引用的架构名称与本例中的不同。它现在工作得很好!
[{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: [{
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 2,
__v: 0
},
{
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 1,
__v: 0
}
]
}]
return Project.aggregate([
{ $match: { projectId: 1 }},
{
$lookup: {
from: 'tasks',
localField: 'projectId',
foreignField: 'projectId',
as: 'tasks'
}
},
{ $unwind: '$tasks' }
]).exec();
[{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: {
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 1,
__v: 0
}
},
{
_id: ObjectID {/*ID*/},
projectId: 1,
description: 'Foo',
__v: 0,
tasks: {
_id: ObjectID {/*ID*/},
projectId: 1,
hours: 2,
__v: 0
}
}
]