Mongodb Map Reduce:如何对结果进行分组?

时间:2017-11-07 11:28:43

标签: mongodb mapreduce mongodb-query

我使用map reduce而不是聚合框架,因为我做了一些字符串操作和值检查。

我有一个查询,它返回具有特定操作系统的设备数。例如。我已经实现的一个查询返回一个如下所示的结果:[{"_id":"Android","value":800}, {"_id":"Windows Phone","value":50}]

我已经使用query参数来提升效果。现在我想使用map reduce,结果应该按照设备所在的建筑物进行分组。

数据库结构: 包含多个具有以下属性的文档的集合:OperatingSystemBuilding

  

{       " _id" :ObjectId(" 5a0174c616bcd022e04fcc43"),       " OperatingSystem":" Android",       "建立":xy"}

注意:这是简化的,例如OperatingSystem包含字符串中的版本号,但我已经在处理它了。

到目前为止我尝试过:

let map = function () {
    // some manipulation of property values
    // type checks + error handling
    emit({op: this.operatingSystem, this.building], 1); 
}

let reduce = function (key, values) {
        return Array.sum(values);
}

但结果不是我想要的格式:

  

[{" _id":" Android"," value":222},{" _id":{" operatingSystem":" Windows Phone"," building":" xy"}," value":2},{&#34 ; _id" {" OperatingSystem的":" Android和#34;"建筑":" XY"}"值&# 34;:5}]

结果的问题:密钥应该只是建筑物,属性应该是具有特定建筑物计数的操作系统,第一个条目是无用的,不应该是结果的一部分。

结果应如下所示:

[{"Building": "xy", "deviceCounts": [{"Android": 50}, "Windows Phone": 20}]}, {"Building: zz" //......

如何通过操作系统和同一属性中的bulding来构建密钥并节省设备数量?

1 个答案:

答案 0 :(得分:0)

如果您需要所需的输出格式(您没有提到正在进行的字符串操作),则可以使用聚合框架。例如:

> db.test.find()
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Windows Phone", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Windows Phone", "Building": "xy" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "zz" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "zz" }
{ "_id": ObjectId(...), "OperatingSystem": "Android", "Building": "zz" }
{ "_id": ObjectId(...), "OperatingSystem": "Windows Phone", "Building": "zz" }
{ "_id": ObjectId(...), "OperatingSystem": "Windows Phone", "Building": "zz" }

在此示例中,构建Windows Phone中有2 Android和5 xy,构建Windows Phone中有2 Android和3 zz }。

我发现这个聚合管道将输出所需的格式:

db.test.aggregate([
    // count occurences of building & operating system combination
    {$group: {_id: {building: '$Building', os: '$OperatingSystem'}, count: {$sum:1}}},
    // group by building
    {$group: {_id: '$_id.building', device: {$push: {k: '$_id.os', v: '$count'}}}},
    // project into the desired format
    {$project: {Building: '$_id', deviceCounts: {$arrayToObject: '$device'}}}
])

示例输出是:

{ "_id": "xy", "Building": "xy", "deviceCounts": { "Windows Phone": 2, "Android": 5 } }
{ "_id": "zz", "Building": "zz", "deviceCounts": { "Android": 3, "Windows Phone": 2 } }

请注意,输出中还有一个_id字段,因为MongoDB要求每个文档都有一个_id字段。

使用的聚合管道($arrayToObject)仅在MongoDB 3.4系列中可用。