给定文件如
{
_id: 'abcd',
userId: '12345',
activities: [
{ status: 'login', timestamp: '10000001' },
{ status: 'logout', timestamp: '10000002' },
{ status: 'login', timestamp: '10000003' },
{ status: 'logout', timestamp: '10000004' },
]
}
我正在尝试创建一个管道,例如所有在两个时间戳之间记录了最新登录/注销事件的用户都将被返回。例如,如果两个时间戳值介于 10000002
和 10000003
之间,则预期的文档应该是
{
_id: 'abcd',
userId: '12345',
login: '10000003',
logout: '10000002'
}
如果两个时间戳值介于-1
和10000001
之间,则预期的文档应该是:
{
_id: 'abcd',
userId: '12345',
login: '10000001',
logout: null
}
等等
我知道它与聚合有关,我需要 $unwind
等,但我不确定其余部分,即评估同一文档数组中的两个字段
最佳答案
您可以尝试以下聚合:
db.col.aggregate([
{
$unwind: "$activities"
},
{
$match: {
$and: [
{ "activities.timestamp": { $gte: "10000001" } },
{ "activities.timestamp": { $lte: "10000002" } }
]
}
},
{
$sort: {
"activities.timestamp": -1
}
},
{
$group: {
_id: "$_id",
userId: { $first: "$userId" },
activities: { $push: "$activities" }
}
},
{
$addFields: {
login: { $arrayElemAt: [ { $filter: { input: "$activities", as: "a", cond: { $eq: [ "$$a.status", "login" ] } } } , 0 ] },
logout: { $arrayElemAt: [ { $filter: { input: "$activities", as: "a", cond: { $eq: [ "$$a.status", "logout" ] } } } , 0 ] }
}
},
{
$project: {
_id: 1,
userId: 1,
login: { $ifNull: [ "$login.timestamp", null ] },
logout: { $ifNull: [ "$logout.timestamp", null ] }
}
}
])
我们需要使用 $unwind + $sort + $group以确保我们的事件将按时间戳排序。在 $unwind
之后你可以使用 $match应用过滤条件。然后你可以使用$filter与 $arrayElemAt获取过滤数组的第一个(最新)值。在最后一个 $project
中,您可以显式使用 $ifNull (否则,如果没有值,将跳过 JSON 键)
关于mongodb - 从 MongoDB 中的同一数组返回包含两个字段的文档,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53415876/