考虑我有如下的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
答案 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
}
]
},
...
]
现在,您可以使用服务器脚本来获取最大天数。或者您可以编写另一个管道操作,该操作将获得图案化连续元素的最大差异。
答案 2 :(得分:0)
我相信,如果您为特定用户执行每个unsubscribe
操作之后的每个时间段,则会更加准确。举例说明,如果用户A每次执行unsubscribe
,您将计算最后的订阅期并在订阅用户联接上对其进行更新。我认为您可以管理每个用户是否有多个订阅,并且始终可以跟踪每个客户的每个订阅的确切时间。
但是,您可以通过在准确的时间片中运行的作业来跟踪该时间。