我有一个庞大的数据集(以百万计),格式如下:
{
"userid" : "codejammer",
"data" : [
{"type" : "number", "value" : "23748"},
{"type" : "message","value" : "one"}
]
}
我希望message
计算one
userid
codejammer
- var map = function(){
emit(this.data[0].value,1);
}
以下是我正在使用的mapreduce函数: 地图:
var reduce = function(key,values){
return Array.sum(values);
}
减少
var options = {
"query":{"userid" : "codejammer",
"data.type" : "message"},
"out" : "aggregrated"
}
选项
{
"_id" : 23748,
"value" : 1
}
mapreduce函数使用以下输出成功执行:
{
"_id" : one,
"value" : 1
}
但是,我期待以下输出:
query
选项中的data.type : "message"
过滤器,即使我特别要求query
有没有办法在{{1}}过滤器中使用projection运算符来仅获取数组中所需的项?
非常感谢你的帮助。
答案 0 :(得分:2)
你最好用aggregate
做这件事。在这种情况下不需要mapReduce,聚合框架作为本机代码运行,并且比通过JavaScript解释器运行要快得多:
db.collection.aggregate([
// Still makes sense to match the documents to reduce the set
{ "$match": {
"userid": "codejammer",
"data": { "$elemMatch": {
"type": "message", "value": "one"
}}
}},
// Unwind to de-normalize the array content
{ "$unwind": "$data" },
// Filter the content of the array
{ "$match": {
"data.type": "message",
"data.value": "one"
}},
// Count all the matching entries
{ "$group": {
"_id": null,
"count": { "$sum": 1 }
}}
])
当然,如果你真的只有一个"消息"在你的"数据"数组变得非常简单:
db.collection.aggregate([
// Match the documents you want
{ "$match": {
"userid": "codejammer",
"data": { "$elemMatch": {
"type": "message", "value": "one"
}}
}},
// Simply count the documents
{ "$group": {
"_id": null,
"count": { "$sum": 1 }
}}
])
但当然这与此无异:
db.collection.find({
"userid": "codejammer",
"data": { "$elemMatch": {
"type": "message", "value": "one"
}}
}).count()
因此虽然有一种方法可以使用mapReduce来实现这一点,但显示的其他方式要好得多。特别是在新发布的2.6版本及以上版本中。在较新的版本中,聚合管道可以利用磁盘存储来处理非常大的集合。
但是要使用mapReduce
获取计数,你基本上是以错误的方式进行计算。投影不能作为输入,因此您需要从结果中取出元素。我还是会考虑你的数组中可能有多个匹配值,即使不是这样:
db.collection.mapReduce(
function() {
var userid = this.userid;
this.data.forEach(function(doc) {
if ( doc == condition )
emit( userid, 1 );
});
},
function(key,values) {
return values.length;
},
{
"query": {
"userid": "codejammer",
"data": { "$elemMatch": {
"type": "message", "value": "one"
}}
},
"scope": {
"condition": {"type" : "message", "value" : "one"}
},
"out": { "inline": 1 }
}
)
所以以同样的方式发出"发出"在数据数组中找到符合条件的文档时公用键的值。所以你不能只投射匹配的元素,你得到所有这些元素并以这种方式过滤。
由于您只期望一个结果,因此实际输出到集合没有任何意义,因此只需将其作为一个结果发送出去。
但基本上,如果必须这样做,请使用聚合方法。