Map减少需要与前一行关联的查询类型

时间:2013-05-10 11:04:58

标签: mongodb

我有以下架构:

  • 客户ID
  • 位置名称
  • 访问时间
  • 购买//这是一个列表

由于这是一个非结构化数据,像MongoDB这样的Flat DB非常适合。我们正在使用MongoDB。

此数据存储各个位置的客户访问信息。假设我想知道特定日期的重复访问次数。重复访问的逻辑很简单:如果一个人今天访问了一家商店,之前曾访问过同一家商店,那么他就是该商店的重复访客。

我有一个逻辑用,我可以找出重复访客的数量:

查询:按位置ID ASC,客户ID ASC,'访问时间'ASC选择*来自架构顺序

上述查询的数据排序后,如果LocationID和客户ID匹配,我们可以比较“访问时间”前一行和下一行。如果是>的差异> 1天,重复访问。

由于此数据非常庞大,因此连接类型的查询效率非常低(即使在MongoDB中也是如此)。

现在我明白MongoDB中有map reduce框架。但是,是否可以在先前记录和当前记录之间进行比较,并根据它进行一些计算,之后可以触发map / reduce?

示例:

  • 客户A在第1天访问商店B //无需重复访问
  • 客户A在第1天再次访问商店B //仍然没有重复访问
  • 客户A在第2天访问商店B //在第2天重复访问该客户A
  • 客户A在第2天访问商店B //已经算作第2天的重复访问
  • 客户A在第3天访问商店B //在第3天重复访问该客户

  • 客户C在第2天访问商店B //首次访问客户C,而不是重复访问

  • 客户C在第2天再次访问商店B //访问的第一天,而不是重复访问
  • 客户C在第3天访问商店B //在第3天重复访问
  • 客户C在第4天访问商店B //在第4天重复访问

  • 客户D在第5天访问商店B //首次访问,而非重复访问

重复访问的最终结果:

  • 商店B,第1天:0重复访问
  • 商店B,第2天:2重复访问
  • 商店B,第3天:2重复访问
  • 商店B,第4天:1重复访问
  • 商店B,第5天:0重复访问

1 个答案:

答案 0 :(得分:0)

如果您在关系数据库中执行此操作,则不会逐行比较访问,而是使用聚合查询来查找重复访问(使用SELECT ... GROUP BY),因此您应该以相同的方式执行此操作MongoDB的。

首先,您需要按每家商店每天汇总每次访问次数:

group1 = { "$group" : {
        "_id" : {
            "c" : "$clientId",
            "l" : "$location",
            "day" : {
                "y" : {
                    "$year" : "$tov"
                },
                "m" : {
                    "$month" : "$tov"
                },
                "d" : {
                    "$dayOfMonth" : "$tov"
                }
            }
        },
        "visits" : {
            "$sum" : 1
        }
    }
};

编辑,因为您只想重复下一个DAYS,您将按客户,按商店进行分组,并计算该客户访问该商店的不同DAYS数量:

group2 = {"$group" : 
    {"_id" : {
        "c" : "$_id.c",
        "s" : "$_id.l"
    },
    "totalDays" : {
        "$sum" : 1
    }
} };

然后,您希望仅包含上面的记录,其中同一个客户在多天内访问同一商店多次:

match = { "$match" : { "totalDays" : { "$gt" : 1 } } };

以下是使用上述管道操作的示例数据集和此聚合的结果:

> db.visits.find({},{_id:0,purchases:0}).sort({location:1, clientId:1, tov:1})
{ "clientId" : 1, "location" : "l1", "tov" : ISODate("2013-01-01T20:00:00Z") }
{ "clientId" : 1, "location" : "l1", "tov" : ISODate("2013-01-01T21:00:00Z") }
{ "clientId" : 1, "location" : "l1", "tov" : ISODate("2013-01-03T20:00:00Z") }
{ "clientId" : 2, "location" : "l1", "tov" : ISODate("2013-01-01T21:00:00Z") }
{ "clientId" : 3, "location" : "l1", "tov" : ISODate("2013-01-01T21:00:00Z") }
{ "clientId" : 3, "location" : "l1", "tov" : ISODate("2013-01-02T21:00:00Z") }
{ "clientId" : 1, "location" : "l2", "tov" : ISODate("2013-01-01T23:00:00Z") }
{ "clientId" : 3, "location" : "l2", "tov" : ISODate("2013-01-02T21:00:00Z") }
{ "clientId" : 3, "location" : "l2", "tov" : ISODate("2013-01-02T21:00:00Z") }
{ "clientId" : 1, "location" : "l3", "tov" : ISODate("2013-01-03T20:00:00Z") }
{ "clientId" : 2, "location" : "l3", "tov" : ISODate("2013-01-04T20:00:00Z") }
{ "clientId" : 4, "location" : "l3", "tov" : ISODate("2013-01-04T20:00:00Z") }
{ "clientId" : 4, "location" : "l3", "tov" : ISODate("2013-01-04T21:00:00Z") }
{ "clientId" : 4, "location" : "l3", "tov" : ISODate("2013-01-04T22:00:00Z") }

> db.visits.aggregate(group1, group2, match)
{
    "result" : [
    {
        "_id" : {
            "c" : 3,
            "s" : "l1"
        },
        "totalDays" : 2
    },
    {
        "_id" : {
            "c" : 1,
            "s" : "l1"
        },
        "totalDays" : 2
    }
    ],
    "ok" : 1
}