2017-10-08 50 views
1

我简化了我的具体问题,所以它更容易理解,但我想汇总的数据是一个视频播放页面上的用户活动,它看起来像这样:有没有办法在聚合过程中获取和设置控制变量?

{_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”,当“视频播放”事件出现时设置为true,并且在“视频暂停”的情况下设置为false,然后只有在设置为true时,才会将“Click Feature 1”事件添加到计数中。

有没有办法做到这样的事情?

+1

更好地流,做在应用端 – sidgate

+0

我认为这是棘手的做,在我的情况,我有一个B计划,但我真的很好奇,想知道如果这样的事情是可能的 –

回答

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 
    ] 
    } 
]) 

您可以通过添加额外的字段“计数”来限制管理阵列生长的任何事件,你可以在一个文档中存储。

对于选定的时间片,您可以有多个文档。

这将简化到下面的聚合。

以下聚合迭代超过video_play_events并过滤每个播放和暂停对的所有点击功能(plpu)。

$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的文件限制的风险。

您可以使用异步模块运行具有适当过滤器的并行查询,以包含要聚合的数据,然后由客户端逻辑对所有部分进行计数。

+0

非常感谢您!所以不幸的是,我试图测试这个,但后来我意识到我与mongodb 5.2卡住和$ indexOfArray是不会工作。所以现在我想我可能不得不重新设计从客户端发送的内容,或者我必须使用mapReduce。 –

相关问题