使用对象数组查找 [英] Lookup with array of Objects
问题描述
我试图填充引用另一个集合的文档的两个对象数组.但是,结果中它总是显示为空数组,这让我感到惊讶.我在这里做错了什么?有没有更好的方法来填充" uploaded_files
和 file_history
?
I am trying to populate two object arrays of my document which reference to another collection. However it always appears as an empty array in the results which surprises me. What am I doing wrong here? Is there a better way to 'populate' uploaded_files
and file_history
?
这是我的汇总声明:
Project.aggregate(
{ $match: {"project_id": projectId}},
{ $addFields: {
uploaded_files: {
$filter: {
input: '$uploaded_files',
as: 'uploadedFile',
cond: {$eq: ['$$uploadedFile.upload_id', uploadId]}
}
},
file_history: {
$filter: {
input: '$file_history',
as: 'revision',
cond: {$eq: ['$$revision.upload_id', uploadId]}
}
},
}},
{ $lookup: {
from: 'users',
localField: 'owner',
foreignField: '_id',
as: 'owner'
}},
{ $lookup: {
from: 'files',
localField: 'uploaded_files.file',
foreignField: '_id',
as: 'test'
}},
{ $lookup: {
from: 'files',
localField: 'file_history.file',
foreignField: '_id',
as: 'test2'
}},
{ $unwind: '$owner' },
{ $limit: 1 }
).then(projects => {
if (projects.length == 0)
return res.status(404).send({ error: "Couldn't find a project with this id" })
let project = projects[0]
})
我的文档如下:
{
"_id" : ObjectId("5935a41f12f3fac949a5f925"),
"project_id" : 13,
"updated_at" : ISODate("2017-07-09T19:41:51.396Z"),
"created_at" : ISODate("2017-06-05T18:34:07.150Z"),
"owner" : ObjectId("591eea4439e1ce33b47e73c3"),
"name" : "Demo project",
"uploaded_files" : [
{
"display_name" : "001.jpg",
"file" : ObjectId("596286ff7d3a594ed4797848"),
"upload_id" : ObjectId("596286ff7d3a594ed4797849"),
"created_at" : ISODate("2017-07-09T19:41:51.000Z")
}
],
"file_history" : [
{
"display_name" : "001.jpg",
"file" : ObjectId("596286ff7d3a594ed4797848"),
"upload_id" : ObjectId("596286ff7d3a594ed4797849"),
"created_at" : ISODate("2017-07-09T19:41:51.000Z")
}
]
}
推荐答案
您基本上需要 $ lookup
.
You basically need to $unwind
the array first. MongoDB cannot yet work with the "inner" property of an object within an array as a source for $lookup
.
为了提高效率,我们确实应该使用 $ concatArrays 代码>
首先加入"数组源,然后仅一个
Also for efficiency we really should use $concatArrays
first to "join" the array source, and then only do one $lookup
operation:
Project.aggregate([
{ "$match": { "project_id": projectId} },
{ "$project": {
"project_id": 1,
"updated_at": 1,
"created_at": 1,
"owner": 1,
"name": 1,
"combined": {
"$concatArrays": [
{ "$map": {
"input": {
"$filter": {
"input": "$uploaded_files",
"as": "uf",
"cond": { "$eq": ["$$uf.upload_id", uploadId ] }
}
},
"as": "uf",
"in": {
"$arrayToObject": {
"$concatArrays": [
{ "$objectToArray": "$$uf" },
[{ "k": "type", "v": "uploaded_files" }]
]
}
}
}},
{ "$map": {
"input": {
"$filter": {
"input": "$file_history",
"as": "fh",
"cond": { "$eq": ["$$fh.upload_id", uploadId ] }
}
},
"as": "fh",
"in": {
"$arrayToObject": {
"$concatArrays": [
{ "$objectToArray": "$$fh" },
[{ "k": "type", "v": "file_history" }]
]
}
}
}}
]
}
}},
{ "$unwind": "$combined" },
{ "$lookup": {
"from": "files",
"localField": "combined.file",
"foreignField": "_id",
"as": "combined.file"
}},
{ "$unwind": "$combined.file" },
{ "$lookup": {
"from": "users",
"localField": "owner",
"foreignField": "_id",
"as": "owner"
}},
{ "$unwind": "$owner" },
{ "$group": {
"_id": "$_id",
"project_id": { "$first": "$project_id" },
"updated_at": { "$first": "$updated_at" },
"created_at": { "$first": "$created_at" },
"owner": { "$first": "$owner" },
"name": { "$first": "$name" },
"combined": { "$push": "$combined" }
}},
{ "$project": {
"project_id": 1,
"updated_at": 1,
"created_at": 1,
"owner": 1,
"name": 1,
"uploaded_files": {
"$filter": {
"input": "$combined",
"as": "cf",
"cond": { "$eq": [ "$$cf.type", "uploaded_files" ] }
}
},
"file_history": {
"$filter": {
"input": "$combined",
"as": "cf",
"cond": { "$eq": [ "$$cf.type", "file_history" ] }
}
}
}}
])
简而言之
-
将两个数组放在源上并标记它们,然后执行
$ lookup
以及合并后的详细信息和$ unwind
> 那个执行
$ lookup
以及其他$ unwind 代码>
那个$ group
将文档与单个数组一起返回.$group
the document back together with a single array.$ filter
通过标签名称"或类型"字段添加,以分隔"数组.$filter
by the "tag names" or "type" field we added to "separate" the arrays.只需在每个数组上使用
$ unwind
,然后执行"join"并重新组合在一起,就可以遵循相同的过程.但是,实际上,除了首先简单地组合"之外,还需要更多的步骤.You can follow the same sort of process just be simply using
$unwind
on each array, then doing the "join" and grouping back together. But really that needs a lot more steps, than simply "combining" in the first place.还要注意,在服务器上进行处理时,
$ lookup
后跟$ unwind
.有关详细信息,请参见聚合管道优化./p>Also note that
$lookup
followed by$unwind
is actually treated as one pipeline stage when processed on the server. See Aggregation Pipeline Optimization for details这篇关于使用对象数组查找的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!