给出诸如
的文档{
_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
,依此类推,但是我不确定其余的事情,即评估同一文档数组中的两个字段
答案 0 :(得分:1)
您可以尝试以下汇总:
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密钥将被跳过)
答案 1 :(得分:1)
您可以使用以下汇总
将$unwind
和$lte
与$gte
聚合一起使用,而不是$fitler
。
db.collection.aggregate([
{ "$project": {
"userId": 1,
"login": {
"$max": {
"$filter": {
"input": "$activities",
"cond": {
"$and": [
{ "$gte": ["$$this.timestamp", "10000001"] },
{ "$lte": ["$$this.timestamp", "10000004"] },
{ "$lte": ["$$this.status", "login"] }
]
}
}
}
},
"logout": {
"$max": {
"$filter": {
"input": "$activities",
"cond": {
"$and": [
{ "$gte": ["$$this.timestamp", "10000001"] },
{ "$lte": ["$$this.timestamp", "10000004"] },
{ "$lte": ["$$this.status", "logout"] }
]
}
}
}
}
}}
])