次のような特定のドキュメント
{
_id: 'abcd',
userId: '12345',
activities: [
{ status: 'login', timestamp: '10000001' },
{ status: 'logout', timestamp: '10000002' },
{ status: 'login', timestamp: '10000003' },
{ status: 'logout', timestamp: '10000004' },
]
}
2つのタイムスタンプの間に最新のログイン/ログアウトアクティビティが記録されているすべてのユーザーが返されるようなパイプラインを作成しようとしています。たとえば、2つのタイムスタンプ値がとの間10000002
にある10000003
場合、期待されるドキュメントは次のようになります。
{
_id: 'abcd',
userId: '12345',
login: '10000003',
logout: '10000002'
}
2つのタイムスタンプ値がとの間-1
にある10000001
場合、予想されるドキュメントは次のようになります。
{
_id: 'abcd',
userId: '12345',
login: '10000001',
logout: null
}
等。
集計に関係していることはわかっていますし、必要なこと$unwind
などもありますが、残りの部分、つまり同じドキュメント配列から2つのフィールドを評価することについてはよくわかりません。
以下の集計を試すことができます。
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 ] }
}
}
])
私たちは、使用する必要があります$アンワインド+ $ソート+ $グループを私たちの活動は、タイムスタンプでソートされますことを確認します。$ matchを$unwind
使用してフィルタリング条件を適用した後。次に、$ filterを$ arrayElemAtとともに使用して、フィルター処理された配列の最初の(最新の)値を取得できます。最後に、明示的に$ ifNullを使用できます(そうしないと、値がない場合にJSONキーがスキップされます)$project
この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。
侵害の場合は、連絡してください[email protected]
コメントを追加