MongoDB聚合基于用户ID和时间段

时间:2018-03-20 22:53:49

标签: mongodb mongodb-query aggregation-framework

我想实现像

这样的东西
{ _id: "A", count: 2 }
{ _id: "B", count: 1 }

来自

{ userId: "A", timeStamp: "12:30PM" } <- start of 5 min interval A: 1
{ userId: "B", timeStamp: "12:30PM" } <- start of 5 min interval B: 1
{ userId: "B", timeStamp: "12:31PM" } <- ignored
{ userId: "A", timeStamp: "12:32PM" } <- ignored
{ userId: "B", timeStamp: "12:33PM" } <- ignored
{ userId: "A", timeStamp: "12:37PM" } <- start of next 5 min A : 2

它基于userId进行分组,然后在userId为group之后,每5分钟触发一次计数。

例如:在午夜开始的任何5分钟内,无限数量的集合可以在00:00到00:05之间有一个timeStamp,但只会被计为1次点击。

希望我能清楚地解释这一点。

我可以通过userId分组并获得一般的计数,但设置计数条件似乎很棘手。

2 个答案:

答案 0 :(得分:2)

您可以尝试$bucket$addToSet - 缺点是您必须手动指定所有范围:

db.col.aggregate([
  {
    $bucket: {
      groupBy: "$timeStamp",
      boundaries: [ "12:30PM", "12:35PM", "12:40PM", "12:45PM", "12:50PM", "12:55PM", "13:00PM" ],
      output: {
        "users" : { $addToSet: "$userId" }
      }
    }
  },
  {
    $unwind: "$users"
  },
  {
    $group: { _id: "$users", count: { $sum: 1 } }
  }
])

答案 1 :(得分:1)

如果你有mongo 3.6,那么Micki的解决方案会更好 如果你有mongo 3.4,你可以使用$ switch。 显然你需要在当天添加所有案例。

db.getCollection('user_timestamps').aggregate(
{
    $group: {
        _id: '$userId',
        timeStamp: {$push: '$timeStamp'}
    }
},
{
    $project: {
        timeStamps: {
            $map: {
                input: '$timeStamp',
                as: 'timeStamp',
                in: {
                     $switch: {
                        branches: [
                            {
                                case: {
                                    $and: [
                                        {$gte: ['$$timeStamp', '12:30PM']},
                                        {$lt: ['$$timeStamp', '12:35PM']}
                                    ]
                                },
                                then: 1
                             },
                             {
                                case: {
                                    $and: [
                                        {$gte: ['$$timeStamp', '12:35PM']},
                                        {$lt: ['$$timeStamp', '12:40PM']}
                                    ]
                                },
                                then: 2
                             }
                        ],
                        default: 0
                     }
                }
            }
        }
    }
},
{
    $unwind: '$timeStamps'
},
{
    $group: {
        _id: '$_id',
        count: {
            $addToSet: '$timeStamps'
        }

    }
},
{
    $project: {
        _id: true,
        count: {$size: '$count'}
    }
}
)

如果您没有mongo 3.4,可以用

替换$ switch
cond: [
   {
       $and: [
           {$gte: ['$$timeStamp', '12:30PM']},
           {$lt: ['$$timeStamp', '12:35PM']}
       ]
   },
   1,
   {
       cond: [
           {
               $and: [
                   {$gte: ['$$timeStamp', '12:35PM']},
                   {$lt: ['$$timeStamp', '12:40PM']}
               ]
           },
           2,
           0
       ]
   }
]