我已经简化了我的具体问题,因此更容易理解,但我想要聚合的数据是视频播放器页面上的用户事件,它看起来像这样:
{_id:"5963796a46d12ed9891f8c80",eventName:"Click Freature 1",creation:1499691279492},
{_id:"59637a5a46d12ed9891f8e0d",eventName:"Video Play",creation:1499691608106},
{_id:"59637a9546d12ed9891f8e90",eventName:"Click Freature 1",creation:1499691664633},
{_id:"59637c0f46d12ed9891f9146",eventName:"Video Pause",creation:1499692055335}
因此,事件是按照时间顺序保持一致的。假设我想计算用户点击功能1的次数,但仅限于视频正在播放的次数。
我相信我必须有一些控制变量,如“isVideoPlaying”,当“Video Play”事件出现时设置为true,如果是“Video Pause”则设置为false,然后添加“Click Feature 1”事件只有在设置为ture时才会计入。
有没有办法做那样的事情?
答案 0 :(得分:1)
有没有办法获取和设置控制变量 聚合过程?
不,在执行聚合管道时无法跟踪上一个/下一个。
我们的想法是将每个事件的事件转换为自己的时间数组值。
您有两种选择。
击穿
Video Play : [1,5,7]
Video Pause : [3,6,10]
Features : [2,4,8,9]
Play-Features : 2 8,9
Video play-pause pair : [1,3],[5,6],[7,10]
Pause-Features : 4
Video pause-play pair : [3,5],[6,7],[10,-]
预期产出
{count:3}
第一个选项:(您在聚合管道中完成所有工作)
使用额外阶段将文档转换为事件数组结构。
考虑以下文件
db.collection.insertMany([
{eventName:"Video Play",creation:1},
{eventName:"Click Features 1",creation:2},
{eventName:"Video Pause",creation:3},
{eventName:"Click Features 1",creation:4},
{eventName:"Video Play",creation:5},
{eventName:"Video Pause",creation:6},
{eventName:"Video Play",creation:7},
{eventName:"Click Features 1",creation:8},
{eventName:"Click Features 1",creation:9},
{eventName:"Video Pause",creation:10}
]);
您可以使用以下聚合
下面的聚合使用两个$group
阶段将事件转换为其时间数组,然后将$project
阶段转换为项目($let
)将每个事件创建数组转换为变量。
有关$let
内的逻辑说明,请参阅选项2
db.collection.aggregate([
{
"$sort": {
"eventName": 1,
"creation": 1
}
},
{
"$group": {
"_id": "$eventName",
"creations": {
"$push": "$creation"
}
}
},
{
"$group": {
"_id": "null",
"events": {
"$push": {
"eventName": "$_id",
"creations": "$creations"
}
}
}
},
{
"$project": {
"count": {
"$let": {
"vars": {
"video_play_events": {
"$arrayElemAt": [
"$events.creations",
{
"$indexOfArray": [
"$events.eventName",
"Video Play"
]
}
]
},
"click_features_event": {
"$arrayElemAt": [
"$events.creations",
{
"$indexOfArray": [
"$events.eventName",
"Click Features 1"
]
}
]
},
"video_pause_events": {
"$arrayElemAt": [
"$events.creations",
{
"$indexOfArray": [
"$events.eventName",
"Video Pause"
]
}
]
}
},
"in": {*}
}
}
}
}
])
*此时您为每个事件都有事件创建数组。在汇总代码下方插入并将$video_play_events
替换为$$video_play_events
,依此类推,以便从$let
阶段访问变量。
第二个选项:(您将事件保存在自己的数组中)
db.collection.insert([
{
"video_play_events": [
1,
5,
7
],
"click_features_event": [
2,
4,
8,
9
],
"video_pause_events": [
3,
6,
10
]
}
])
您可以通过添加额外字段" count"来管理数组增长。限制您可以存储在一个文档中的事件的数量。
您可以为选定的时间片提供多个文档。
这将简化聚合到下面。
以下聚合重复video_play_events
并过滤每个播放和暂停对的所有点击功能(pl
和pu
)。
$size
不计算每个播放和暂停对之间的要素元素,然后$map
+ $sum
计算所有播放暂停对的所有要素事件。
db.collection.aggregate([
{
"$project": {
"count": {
"$sum": {
"$map": {
"input": {
"$range": [
0,
{
"$subtract": [
{
"$size": "$video_play_events"
},
1
]
}
]
},
"as": "z",
"in": {
"$let": {
"vars": {
"pl": {
"$arrayElemAt": [
"$video_pause_events",
"$$z"
]
},
"pu": {
"$arrayElemAt": [
"$video_play_events",
{
"$add": [
1,
"$$z"
]
}
]
}
},
"in": {
"$size": {
"$filter": {
"input": "$click_features_event",
"as": "fe",
"cond": {
"$and": [
{
"$gt": [
"$$fe",
"$$pl"
]
},
{
"$lt": [
"$$fe",
"$$pu"
]
}
]
}
}
}
}
}
}
}
}
}
}
}
])
注意:
根据您在两种情况下尝试聚合的文档数量,您可能会遇到16 MB文档限制的风险。
您可以使用异步模块运行具有适当过滤器的并行查询,以包含您正在聚合的数据,然后使用客户端逻辑来计算所有部分。