使用MongoDB的聚合框架查找活动用户

时间:2018-01-15 07:43:52

标签: mongodb aggregation-framework

我有两个收藏集 - customerstrips

客户中的示例文档,其中_id是分配给每个客户的唯一ID:

{
    "_id": ObjectId("59caa2660d09740010eccfde")
}

行程中的示例文档,其中userId是旅行客户的_idduration是行程持续时间,以分钟为单位endtime 1}}是特定旅行结束的时间(_id这里并不重要):

{
    "_id" : ObjectId("59fe73be50fe7600169bcdb5"),
    "userId": ObjectId("59caa2660d09740010eccfde"),
    "duration": NumberInt(54),
    "endtime": ISODate("2017-11-03T08:14:45.193+0000")
}

使用$lookup到“左外连接”tripscustomers时,我有几百个文档,每个客户都有与之相关的行程(零个或多个):

{
    "_id": ObjectId("59caa2660d09740010eccfde"),
    "trips": [
      {
          "_id" : ObjectId("59fe73be50fe7600169bcdb5"),
          "userId": ObjectId("59caa2660d09740010eccfde"),
          "duration": NumberInt(54),
          "endtime": ISODate("2017-11-03T08:14:45.193+0000")
      },
      {
          "_id" : ObjectId("5a5acb708e303e00109820ac"),
          "userId": ObjectId("59caa2660d09740010eccfde"),
          "duration": NumberInt(32),
          "endtime": ISODate("2018-01-14T03:15:59.207+0000")
      }
    ]
}

我想获取所有活跃客户,其中活跃客户是以下任何人:

  • 每周至少进行7次旅行或每周有5小时的旅行时间
  • 在过去4周内维持上述至少2周

1 个答案:

答案 0 :(得分:1)

您希望将 $lookup 管道阶段作为分组计算聚合的旅行集合后的最后一个或最后一个,然后进行过滤。

因此,对于第一个条件,您需要从旅行集合中获取所有过去四周的所有文档,将它们按userId分组并间隔一周并汇总时间:

var fourWeeksAgo = new Date();
fourWeeksAgo.setDate(fourWeeksAgo.getDate() - 28);

// var fourWeeksAgo = moment().subtract(4, "weeks").toDate();

db.trips.aggregate([
    { "$match": { "endtime": { "$gte": fourWeeksAgo } } },
    {
        "$group": {
            "_id": {
                "user": "$userId",
                "weekInterval": {
                    "$subtract": [
                        { 
                            "$subtract": ["$endtime", new Date("1970-01-01")] 
                        },
                        { 
                            "$mod": [
                                { "$subtract": ["$endtime", new Date("1970-01-01")] },
                                1000 * 60 * 60 * 24 * 7
                            ]
                        }
                    ]
                }
            },
            "count": { "$sum": 1 },
            "totalDuration": { "$sum": "$duration" }
        }
    },
    {
        "$group": {
            "_id": "$_id.user",
            "weekCounts": {
                "$push": {
                    "week": "$weekInterval",
                    "count": "$count",
                    "duration": "$totalDuration"
                }
            }
        }
    },
    {
        "$match": {
            "weekCounts.1": { "$exists": true },
            "$or": [
                { "weekCounts.count": { "$gte": 7 } },
                { "weekCounts.duration": { "$gte": 300 } }
            ]
        }
    },
    {
        "$lookup": {
            "from": "users",
            "localField": "_id",
            "foreignField": "_id",
            "as": "user"
        }           
    }
])