我使用map reduce而不是聚合框架,因为我做了一些字符串操作和值检查。
我有一个查询,它返回具有特定操作系统的设备数。例如。我已经实现的一个查询返回一个如下所示的结果:[{"_id":"Android","value":800}, {"_id":"Windows Phone","value":50}]
我已经使用query
参数来提升效果。现在我想使用map reduce,结果应该按照设备所在的建筑物进行分组。
数据库结构:
包含多个具有以下属性的文档的集合:OperatingSystem
,Building
{ " _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来构建密钥并节省设备数量?
答案 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系列中可用。