我有2个集合(带有示例文档):
报告
{
id: "R1",
type: "xyz",
}
reportfiles
{
id: "F1",
reportid: "R1",
time: ISODate("2016-06-13T14:20:25.812Z")
},
{
id: "F14",
reportid: "R1",
time: ISODate("2016-06-15T09:20:29.809Z")
}
正如您所看到的,report
可能有多个reportfiles
。
我想执行查询,匹配报告id
,按原样返回报告文档,另外还有一个存储为reportfile
子文档的附加密钥,其中包含最新time
(没有reportid
会更好,因为它会多余),例如
{
id: "R1",
type: "xyz",
reportfile: {
id: "F14",
reportid: "R1",
time: ISODate("2016-06-15T09:20:29.809Z")
}
}
我的问题是每个报告类型都有自己的一组属性,因此在聚合管道中使用$project
不是最好的方法。
到目前为止,我得到了
db.reports.aggregate([{
$match : 'R1'
}, {
$lookup : {
from : 'reportfiles',
localField : 'id',
foreignField : 'reportid',
as : 'reportfile'
}
}
])
当然以“报告文件”的形式返回给定reportid
的所有文件的列表。如何有效地过滤该列表以获得我需要的唯一元素?
有效 - >我尝试使用$unwind
作为下一个管道步骤但是生成的文档非常可怕而且毫无意义。
提前感谢任何建议!
答案 0 :(得分:1)
您需要在$project
阶段后向汇总管道中添加另一个$lookup
阶段。
{ "$project": {
"id": "R1",
"type": "xyz",
"reportfile": {
"$let": {
"vars": {
"obj": {
"$arrayElemAt": [
{ "$filter": {
"input": "$reportfile",
"as": "report",
"cond": { "$eq": [ "$$report.time", { "$max": "$reportfile.time" } ] }
}},
0
]
}
},
"in": { "id": "$$obj.id", "time": "$$obj.time" }
}
}
}}
$filter
运算符“过滤”$lookup
结果并返回一个包含满足条件的文档的数组。这里的条件是$eq
,当文档具有$max
imum值时,它返回true。
$arrayElemAt
运算符切片 $ filter 的结果,并从数组中返回元素,然后使用{{3}将其分配给变量运算符。在那里,您可以使用$let
轻松访问结果中所需的字段。
答案 1 :(得分:0)
您需要的是在reportfile
集合上运行聚合操作,在reports
集合上执行“加入”,管道 $group
从 $sort
订购的操作(使用 $unwind
)和展平的文档( $lookup
)管道。然后可以使用reportid
对上述结果进行分组,并使用 $first
累加器aoperators输出所需的结果。
以下演示了这种方法:
db.reportfiles.aggregate([
{ "$match": { "reportid": "R1" } },
{
"$lookup": {
"from": 'reports',
"localField" : 'reportid',
"foreignField" : 'id',
"as": 'report'
}
},
{ "$unwind": "$report" },
{ "$sort": { "time": -1 } },
{
"$group": {
"_id": "$reportid",
"type": { "$first": "$report.type" },
"reportfile": {
"$first": {
"id": "$id",
"reportid": "$reportid",
"time": "$time"
}
}
}
}
])
示例输出:
{
"_id" : "R1",
"type" : "xyz",
"reportfile" : {
"id" : "F14",
"reportid" : "R1",
"time" : ISODate("2016-06-15T09:20:29.809Z")
}
}