【问题标题】:mongo find users were subscribed at least n daysmongo find 用户至少订阅了 n 天
【发布时间】:2019-04-15 08:57:21
【问题描述】:

考虑我收集的 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次。

如您所见,我的文档有一个名为 action 的字段。 所以换句话说,我需要为一个至少有 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

【问题讨论】:

  • @ivanivan 请再次阅读问题。我不想要两个特定时间之间的记录。我需要服务至少 x(例如 2)天的用户
  • 您的预期输出无法从您的样本集合中获得。并且可以用哪个字段max_subscription_days生成?
  • sudo 代码:每个用户的 max_subscription_days = max(number_of_days(unsub_date - sub_date))
  • @mhndev - 日期比较示例。获取今天,从中减去最小年龄,找到比当天更早的帐户。

标签: php mongodb mongodb-query


【解决方案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

【讨论】:

  • 看,您的查询结果是订阅类型的记录,并且事件日期大于特定日期。但我需要至少 n 天参与服务的用户。考虑用户 A 订阅我的服务并在 3 天后退订。下次用户 A 再次订阅我的服务并在 5 天后取消订阅。所以这个用户的最大订阅天数是 5 。
  • @mhndev ,我已根据您的需要进行了更新,希望对您有所帮助。现在服务器脚本计算会很容易。改进仍然存在。
  • @mhndev ,我建议您将 cursor 与此聚合器一起使用。因为如果您假设有 10k 个用户,那么就会有 10k 个(例如示例)项目。
【解决方案2】:

我相信,如果您在针对特定用户的每个 unsubscribe 操作之后处理每个时间段,会更准确。举例来说,如果用户 A 每次都执行unsubscribe,您将计算最后一个订阅周期,并在订阅-用户连接处更新它。我认为您可以管理每个用户是否有多个订阅,并且您始终可以跟踪每个客户每次订阅的确切时间。

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

【讨论】:

  • 谢谢,我认为这可行,但我应该如何处理我当前的数据?我应该运行后台作业并更新它吗?
  • 填充每个订阅的花费时间可以通过查询来完成,但对于接下来的操作,我认为在您的应用程序中处理可能会更好。我会考虑查询
【解决方案3】:

我认为这可能是您正在寻找的聚合:

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

我用一些示例文档进行了测试,效果很好。希望它对你有用。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-09-04
    • 1970-01-01
    • 1970-01-01
    • 2017-07-07
    • 2020-03-06
    • 2021-08-10
    • 1970-01-01
    相关资源
    最近更新 更多