有没有办法在聚合过程中获取和设置控制变量?

时间:2017-10-08 23:55:25

标签: javascript mongodb aggregation-framework

我已经简化了我的具体问题,因此更容易理解,但我想要聚合的数据是视频播放器页面上的用户事件,它看起来像这样:

{_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时才会计入。

有没有办法做那样的事情?

1 个答案:

答案 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并过滤每个播放和暂停对的所有点击功能(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文档限制的风险。

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