mongo查找用户已订阅至少n天

时间:2018-11-12 15:44:39

标签: php mongodb mongodb-query

考虑我有如下的user_events集合:

[
  {
      "_id" : ObjectId("5be99dd1da8d4a596423a2d2"),
      "user_id" : 203302,
      "action" : "subscribe",
      "created_at" : ISODate("2018-11-12T15:35:45.000Z"),
  },
  {
      "_id" : ObjectId("5be99dd1da8d4a596423a2d2"),
      "user_id" : 203302,
      "action" : "unsubscribe",
      "created_at" : ISODate("2018-10-12T15:35:45.000Z"),
  },
  ...
]

我需要找到至少订阅了n天的用户。 每个用户可以无限制地订阅和取消订阅。 例如,用户A可以订阅100次而取消订阅100次。

如您所见,我的文档有一个名为“操作”的字段。 因此,换句话说,我需要为日期间隔至少为n天的用户查找记录。

所以我的结果是这样的:

[

  {
    "user_id": 2,
    "max_subscription_days": 2
  },
  {
    "user_id(user A)": 5,
    "max_subscription_days": 3
  },
    {
    "user_id": 11,
    "max_subscription_days": 3
  }
]

但是我需要至少服务n天的用户。 考虑用户A订阅了我的服务,并在3天后取消订阅。

,下一次用户A再次订阅我的服务,并在5天后退订。 因此,此用户的最大订阅天数为5。

我的堆栈: mongodb:4.0.0

php:7.2

3 个答案:

答案 0 :(得分:2)

我认为这可能是您正在寻找的汇总:

db.user_events.aggregate([
    {
        $group: {
            _id: "$user_id",
            "events": {
                $push: {
                    $cond: {
                        if: { $eq: [ "$action", "subscribe" ] },
                        then: {"date":"$created_at", "event": "subscribe"},
                        else: {"date":"$created_at", "event": "unsubscribe"}
                    }
                }
            }
        }
    },
    {
        $project : {
            events: { $reverseArray : "$events" }
        }
    },
    {
        $project : {
            user_id: "$_id",
            max_subscription_days: {
                $reduce : {
                    input: "$events",
                    initialValue: {date: null, max: 0},
                    in : {
                        date: {
                            $cond: {
                                if: { $eq : ["$$this.event", "unsubscribe"] },
                                then : "$$this.date",
                                else : null
                            }
                        },
                        max: {
                            $cond: {
                                if: { $eq : ["$$this.event", "unsubscribe"] },
                                then : "$$value.max",
                                else : {
                                    $cond : {
                                        if : { $gt : [ { $divide: [ { $subtract: [ "$$value.date", "$$this.date" ] }, 24 * 60 * 60 * 1000] }, "$$value.max" ] },
                                        then : { $divide: [ { $subtract: [ "$$value.date", "$$this.date" ] }, 24 * 60 * 60 * 1000] },
                                        else : "$$value.max"
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    },
    {
        $match : { "max_subscription_days.max" : { $gt : n } }
    }
])

结果将是:

[
    {
        "_id" : 203302,
        "user_id" : 203302,
        "max_subscription_days" : 10.0
    },
    {
        "_id" : 203301,
        "user_id" : 203301,
        "max_subscription_days" : 4.0
    }
]

我测试了一些示例文档,并且效果很好。希望它对您有用。

答案 1 :(得分:1)

  

聚合函数将返回订阅和取消订阅的列表   日期为user_id的事件

db.getCollection('').aggregate([
     {
       $group:
         {
           _id: "$user_id",

           "subscribe_unsubscribe" :
                        {
                          $push:
                            {
                                $cond: { if: { $eq: [ "$action", "subscribe" ] }, then: {"s":"$created_at"}, else: {"u":"$created_at"} }

                            }
                         }
         }
     }]
   )

输出将类似于

[{
    "_id" : "3334",
    "subscribe_unsubscribe" : [ 
        {
            "s" : 2000-11-12 00:00:00.000Z
        }, 
        {
            "u" : 2000-11-13 00:00:00.000Z
        },
        {
            "s" : 2000-11-16 00:00:00.000Z
        }, 
        {
            "u" : 2000-11-20 00:00:00.000Z
        }
    ]
},
...
]

现在,您可以使用服务器脚本来获取最大天数。或者您可以编写另一个管道操作,该操作将获得图案化连续元素的最大差异。

Checkout mongodDB aggregate

答案 2 :(得分:0)

我相信,如果您为特定用户执行每个unsubscribe操作之后的每个时间段,则会更加准确。举例说明,如果用户A每次执行unsubscribe,您将计算最后的订阅期并在订阅用户联接上对其进行更新。我认为您可以管理每个用户是否有多个订阅,并且始终可以跟踪每个客户的每个订阅的确切时间。

但是,您可以通过在准确的时间片中运行的作业来跟踪该时间。