从MongoDB中的一个查询中获取多个字段数?

时间:2014-06-05 15:51:10

标签: java performance mongodb mapreduce aggregation-framework

我有一系列事件,其结构如下:

{
    "_id" : ObjectId("537b3ff288f4ca2f471afcae"),
    "Name" : "PREMISES MAP DELETED",
    "ScreenName" : "AccessPointActivity",
    "Timestamp" : NumberLong("1392113758000"),
    "EventParams" : "null",
    "TracInfo" : {
            "ApplicationId" : "fa41f204bfc711e3b9f9c8cbb8c502c4",
            "DeviceId" : "2_1VafJVPu4yfdbMWO1XGROjK6iQZhq4hAVCQL837W",
            "UserId" : "pawan",
            "SessionId" : "a8UHE16mowNwNGyuLXbW",
            "WiFiAP" : "null",
            "WiFiStrength" : 0,
            "BluetoothID" : "null",
            "BluetoothStrength" : 0,
            "NetworkType" : "null",
            "NetworkSubType" : "null",
            "NetworkCarrier" : "Idea",
            "Age" : 43,
            "Gender" : "Female",
            "OSVersion" : "16",
            "Manufacturer" : "samsung",
            "Resolution" : "600*976",
            "Platform" : "Android",
            "Latitude" : 40.42,
            "Longitude" : -74,
            "City" : "Monmouth County",
            "CityLowerCase" : "monmouth county",
            "Country" : "United States",
            "CountryLowerCase" : "united states",
            "Region" : "New Jersey",
            "RegionLowerCase" : "new jersey",
            "Time_zone" : "null",
            "PinCode" : "07732",
            "Locale" : ", Paradise Trailer Park",
            "Accuracy" : 0,
            "Timestamp" : NumberLong("1392113758000")
    }
}

他们在不同的屏幕上有很多活动。

我的预期输出如下:

{
    ApplicationId:"fa41f204bfc711e3b9f9c8cbb8c502c4",
    EventName:"PREMISES MAP DELETED",
    Eventcount:300, 
    ScreenviewCount:20,
    DeviceCount:10, 
    UserCount:3 
}

EventCount:它是EventName的计数

ScreenviewCount:每个会话的不同screenName的计数

DeviceCount:它是不同deviceId的计数

UserCount:它是不同userCount的计数

他们将在多个屏幕上显示多个事件(ScreenName)。

目前我正在使用以下方法:

  1. 使用聚合来获取每个事件名称并对其进行计数 例如:

      {    
        _id:
        {
            ApplicationId:"fa41f204bfc711e3b9f9c8cbb8c502c4",
            EventName:"PREMISES MAP DELETED"    
        }
        EventCount:300    
    

    }

  2. 对于上面聚合结果中的每个事件名称,我在while循环中调用以下查询,直到聚合输出包含文档:

  3. a)使用来自聚合输出的eventName进行屏幕视图计数(在事件收集时)的不同查询。

    b)来自聚合输出的不同查询eventName,用于设备计数(在事件收集时)。

    c)来自聚合输出的不同查询eventName,用于用户计数(在事件收集时)。

    问题是它很慢,因为它对聚合输出的每个结果有3个不同的查询。

    他们是否可以通过单一聚合调用或其他方式进行此操作。

    提前谢谢!!!

1 个答案:

答案 0 :(得分:6)

这里你似乎错过的一般情况是得到" distinct" "事件"中文档中各个字段的值总计,您可以使用$addToSet运算符。

A" set"根据定义,它具有所有值"唯一/不同",因此您只想将所有这些可能的值保存在" set"为您的分组级别,然后获得"尺寸"生成的数组,这正是MongoDB 2.6中引入的$size运算符所做的。

db.collection.aggregate([
    { "$group": {
        "_id": {
            "ApplicationId": "$TracInfo.ApplicationId",
            "EventName": "$Name",
        },
        "oScreenViewCount": { 
            "$addToSet": {
                "ScreenName": "$ScreenName",
                "SessionId": "$TracInfo.SessionId",
            }
        },
        "oDeviceCount": { "$addToSet": "$TracInfo.DeviceId" },
        "oUserCount": { "$addToSet": "$TracInfo.UserId" },
        "oEventcount": { "$sum": 1 }
    }},
    { "$project": {
        "_id": 0,
        "ApplicationId": "$_id.ApplicationId",
        "EventName": "$_id.EventName",
        "EventCount": "$oEventCount",
        "ScreenViewCount": { "$size": "$oScreenViewCount" },
        "DeviceCount": { "$size": "$oDeviceCount" },
        "UserCount": { "$size": "$oUserCount" }
    }}
])

MongoDB 2.6之前的版本需要更多工作,使用$unwind$group来计算数组:

db.collection.aggregate([
    { "$group": {
        "_id": {
            "ApplicationId": "$TracInfo.ApplicationId",
            "EventName": "$Name",
        },
        "oScreenviewCount": { 
            "$addToSet": {
                "ScreenName": "$ScreenName",
                "SessionId": "$TracInfo.SessionId",
            }
        },
        "oDeviceCount": { "$addToSet": "$TracInfo.DeviceId" },
        "oUserCount": { "$addToSet": "$TracInfo.UserId" },
        "oEventcount": { "$sum": 1 }
    }},
    { "$unwind": "$oScreeenviewCount" },
    { "$group": {
        "_id": "$_id",
        "oScreenviewCount": { "$sum": 1 },
        "oDeviceCount": { "$first": "$oDeviceCount" },
        "oUserCount": { "$first": "$oUserCount" },
        "oEventcount": { "$first": "$oEventCount" }
    }},
    { "$unwind": "$oDeviceCount" },
    { "$group": {
        "_id": "$_id",
        "oScreenviewCount": { "$first": "$oScreenViewCount" },
        "oDeviceCount": { "$sum": "$oDeviceCount" },
        "oUserCount": { "$first": "$oUserCount" },
        "oEventcount": { "$first": "$oEventCount" }
    }},
    { "$unwind": "$oUserCount" },
    { "$group": {
        "_id": "$_id",
        "oScreenviewCount": { "$first": "$oScreenViewCount" },
        "oDeviceCount": { "$first": "$oDeviceCount" },
        "oUserCount": { "$sum": "$oUserCount" },
        "oEventcount": { "$first": "$oEventCount" }
    }},
    { "$project": {
        "_id": 0,
        "ApplicationId": "$_id.ApplicationId",
        "EventName": "$_id.EventName",
        "EventCount": "$oEventCount",
        "ScreenViewCount": "$oScreenViewCount",
        "DeviceCount": "$oDeviceCount",
        "UserCount": "$oUserCount"
    }}

])

第二个列表中$project的最终用法以及" o"的所有一般用法前缀名称实际上只是用于在结尾处查找结果并确保输出字段顺序与示例结果中的相同。

作为一般性免责声明,您的问题缺乏确定用于这些总计的确切字段或组合的信息,但原则和方法是合理的,应该足够接近相同的实现。

从本质上讲,你得到的是" distinct" "组内的值"通过$addToSet使用任何字段或组合,然后您确定"计数"那些"套"通过任何可用的方式。

比发布许多查询并在客户端代码中合并结果要好得多。