2014-09-22 47 views
9

我有一个文档集合,其中有一个已知值为数字的值,但存储为字符串。改变字段的类型不在我的控制范围之内,但我想在聚合中使用该字段(比如,将其平均)。将字符串转换为MongoDB投影中的数字

看来我应该在分组之前使用投影,并在该投影中根据需要转换字段。我似乎无法得到恰到好处的语法 - 我所尝试的任何一种方法都给了我NaN,或者新的字段在聚合的下一步中完全没有了。

$project: { 
    value: '$value', 
    valueasnumber: ???? 
} 

鉴于上述非常简单的例子,其中$值的所有文档中的内容是字符串类型,而是将解析到一个号码,我该怎么办,使valueasnumber一个新的(不存在)字段它的解析版本是$ value的类型是double吗?

我试着像下面的例子(和十几个类似的东西)的东西:

{ $add: new Number('$value').valueOf() } 
new Number('$value').valueOf() 

难道我完全找错了树?任何帮助将不胜感激!

(要100%清楚,以下是我想如何使用新字段)。

$group { 
    score: { 
     $avg: '$valueasnumber' 
    } 
} 
+1

从MongoDB 2.6开始,你倒霉了。聚合框架中没有可用的数字解析选项。如果该字段代表一个数字,它应该确实存储为一个数字;也许你可以添加另一个字段,这是数字的数字形式?你也可以考虑map/reduce。 – wdberkeley 2014-09-23 14:33:17

+0

感谢大家的评论。我正在尝试两种方法,以了解最佳效果。看起来,聚合框架比map/reduce有更好的性能,因此可能值得维护第二个字段(作为数字),以便按预期使用聚合。 – 2014-09-24 13:05:05

+0

可能重复的[如何将字符串转换为mongodb中的数值](http://stackoverflow.com/questions/29487351/how-to-convert-string-to-numerical-values-in-mongodb) – styvane 2016-12-29 16:44:25

回答

3

之一,我可以想到的方法是使用一个蒙戈壳的javascript通过添加新的号码字段,valuesasnumber现有的文档中(现有的字符串的数目变​​换“值”字段)或修改的文件在新的文档中。然后使用此数字字段进行进一步计算。

db.numbertest.find().forEach(function(doc) { 
    doc.valueasnumber = new NumberInt(doc.value); 
    db.numbertest.save(doc); 
}); 

使用valueasnumber字段数值计算

db.numbertest.aggregate([{$group : 
    {_id : null, 
    "score" : {$avg : "$valueasnumber"} 
    } 
}]); 
2

核心操作是从值字符串转换至其不能在aggregate pipeline operation处理当前数。
mapReduce是下面的替代方案。

db.c.mapReduce(function() { 
    emit(this.groupId, {score: Number(this.value), count: 1}); 
}, function(key, values) { 
    var score = 0, count = 0; 
    for (var i = 0; i < values.length; i++) { 
     score += values[i].score; 
     count += values[i].count; 
    } 
    return {score: score, count: count}; 
}, {finalize: function(key, value) { 
    return {score: value.score/value.count}; 
}, out: {inline: 1}});