【发布时间】:2015-07-14 00:33:12
【问题描述】:
我们在 mongodb 中有字段,其中包含字符串形式的数字,值如“$123,00,89.00”或“1234$”等
是否可以在mongodb中自定义$sum累加器,以便在求和的同时对每个字段值进行一定的处理。如子字符串或正则表达式处理等。
【问题讨论】:
标签: mongodb mapreduce mongodb-query aggregation-framework
我们在 mongodb 中有字段,其中包含字符串形式的数字,值如“$123,00,89.00”或“1234$”等
是否可以在mongodb中自定义$sum累加器,以便在求和的同时对每个字段值进行一定的处理。如子字符串或正则表达式处理等。
【问题讨论】:
标签: mongodb mapreduce mongodb-query aggregation-framework
.mapReduce() 方法正是您所需要的。您不能将aggregation framework 中的值从一种“类型”“转换”为另一种(“转换为字符串”或从Date 转换为数字除外)。
JavaScript 处理意味着您可以将字符串转换为“求和”的值。像这样的事情(对所需的“货币”值的“安全”正则表达式做更多的工作:
db.collection.mapReduce(
function() {
emit(null, this.amount.replace(/\$|,|\./g,"") / 100 );
},
function(key,values) {
return Array.sum(values);
},
{ "out": { "inline": 1 } }
)
或者 .group() 也使用 JavaScript 处理,但它的要求更严格:
db.collection.group({
"key": null,
"reduce": function( curr,result ) {
result.total += curr.amount.replace(/\$|,|\./g,"") /100;
},
"initial": { "total": 0 }
});
因此,JavaScript 处理是您唯一的选择,因为聚合框架不支持此类操作。
数字可以是字符串:
db.junk.aggregate([{ "$project": { "a": { "$substr": [ 1,0,1 ] } } }])
{ "_id" : ObjectId("55a458c567446a4351c804e5"), "a" : "1" }
而Date 可以变成数字:
db.junk.aggregate([{ "$project": { "a": { "$subtract": [ new Date(), new Date(0) ] } } }])
{ "_id" : ObjectId("55a458c567446a4351c804e5"), "a" : NumberLong("1436835669446") }
但是没有其他运算符可以将“字符串”“转换”为“数字”,甚至没有其他运算符可以进行正则表达式替换,如上所示。
如果您想使用.aggregate(),那么您需要将您的数据固定为支持它的格式,即“数字”:
var bulk = db.collection.initializeOrderedBulkOp(),
count = 0;
db.collection.find({ "amount": /\$|,\./g }).forEach(function(doc) {
doc.amount = doc.amount.replace(/\$|,|\./g,"") /100;
bulk.find({ "_id": doc._id }).updateOne({
"$set": { "amount": doc.amount }
});
count++;
// execute once in 1000 operations
if ( count % 1000 == 0 ) {
bulk.execute();
bulk = db.collection.initializeOrderedBulkOp();
}
});
// clean up queued operations
if ( count % 1000 != 0 )
bulk.execute();
然后你可以在你的“数字”数据上使用.aggregate():
db.collection.aggregate([
{ "$group": { "_id": null, "total": { "$sum": "$amount" } } }
])
【讨论】: