Javascript Mongodb:Mapreduce查询筛选器位置运算符

Javascript Mongodb:Mapreduce查询筛选器位置运算符,javascript,node.js,mongodb,mapreduce,aggregation-framework,Javascript,Node.js,Mongodb,Mapreduce,Aggregation Framework,我有一个巨大的数据集(以百万计),格式如下: { "userid" : "codejammer", "data" : [ {"type" : "number", "value" : "23748"}, {"type" : "message","value" : "one"} ] } 我想获得用户ID-编码干扰器 以下是我正在使用的mapreduce函数: 地图: 减少 var reduce = function(key,values){ retur

我有一个巨大的数据集(以百万计),格式如下:

{
  "userid" : "codejammer",
  "data" : [       
   {"type" : "number", "value" : "23748"},
   {"type" : "message","value" : "one"}
  ]
}
我想获得
用户ID
-
编码干扰器

以下是我正在使用的mapreduce函数: 地图:

减少

var reduce = function(key,values){
    return Array.sum(values);
}
选择权

var options = {
             "query":{"userid" : "codejammer",
                 "data.type" : "message"},
             "out" : "aggregrated"
            }
mapreduce函数通过以下输出成功执行:

{
 "_id" : 23748,
  "value" : 1
}
但是,我期望得到以下结果:

{
 "_id" : one,
 "value" : 1
}
选项中的
query
过滤器正在将整个数组发送到map函数,即使我特别要求
data.type:“message”

是否有任何方法可以使用
query
filter中的运算符仅获取数组中所需的项


非常感谢您的帮助。

事实上,与您一起做这件事会更好。在这种情况下,不需要mapReduce,聚合框架作为本机代码运行,比通过JavaScript解释器运行要快得多:

db.collection.aggregate([
//匹配文档以减少集合仍然是有意义的
{“$match”:{
“userid”:“codejammer”,
“数据”:{“$elemMatch”:{
“类型”:“消息”,“值”:“一”
}}
}},
//展开以反规范化数组内容
{“$unwind”:“$data”},
//筛选数组的内容
{“$match”:{
“数据类型”:“消息”,
“data.value”:“一”
}},
//统计所有匹配的条目
{“$组”:{
“_id”:空,
“计数”:{“$sum”:1}
}}
])
当然,如果您的“数据”数组中实际上只有一条“消息”,那么这就变得非常简单:

db.collection.aggregate([
//匹配所需的文档
{“$match”:{
“userid”:“codejammer”,
“数据”:{“$elemMatch”:{
“类型”:“消息”,“值”:“一”
}}
}},
//只需清点文件
{“$组”:{
“_id”:空,
“计数”:{“$sum”:1}
}}
])
但当然,这实际上与此没有什么不同:

db.collection.find({
“userid”:“codejammer”,
“数据”:{“$elemMatch”:{
“类型”:“消息”,“值”:“一”
}}
}).count()
因此,虽然有一种使用mapReduce的方法可以做到这一点,但显示的其他方法要好得多。尤其是在最新发布的2.6版及以上版本中。在较新版本中,聚合管道可以利用磁盘存储来处理非常大的集合

但是用你的方法来计算基本上是错误的。投影不能作为输入,因此需要从结果中取出元素。我仍然认为,即使不是这样的情况下,数组中也可能有不止一个匹配值:

db.collection.mapReduce(
函数(){
var userid=this.userid;
this.data.forEach(函数(doc){
if(doc==条件)
emit(userid,1);
});
},
功能(键、值){
返回值.length;
},
{
“查询”:{
“userid”:“codejammer”,
“数据”:{“$elemMatch”:{
“类型”:“消息”,“值”:“一”
}}
},
“范围”:{
“条件”:{“类型”:“消息”,“值”:“一”}
},
“out”:{“inline”:1}
}
)
因此,当在数据数组中找到与您的条件匹配的文档时,这将以大致相同的方式“发出”公共键的值。所以你不能只投射匹配的元素,你会得到所有的元素,然后用这种方式过滤

因为您只期望一个结果,所以实际输出到集合没有意义,所以只需将其作为一个结果发送出去即可


但基本上,如果必须这样做,请使用聚合方法。

就大小而言,需要进行聚合。如果这次尝试成功,我需要做更复杂的MapReduce:)@Neil,第二个
$match
阶段不是多余的吗?@AnandJayabalan不是。其目的是实际过滤数组的元素。但正如我在扩展时所说,如果实际上只有一个元素,那么只需计算
.find()
@codejammer的结果,您就会发现这里有足够的信息来完成您想要的。如前所述,从2.6版(昨天发布)开始,限制不再存在。@codejammer因为在几乎所有的东西中,你不需要硬编码任何东西,它只是代码中的数据结构,所以即使是函数部分实际上也可以写成字符串。但是如果它更符合您的感受,我将列表更改为使用范围中定义的变量。
{
 "_id" : one,
 "value" : 1
}