【问题标题】:Sum of Substrings in mongodbmongodb中的子串总和
【发布时间】:2015-07-14 00:33:12
【问题描述】:

我们在 mongodb 中有字段,其中包含字符串形式的数字,值如“$123,00,89.00”或“1234$”等

是否可以在mongodb中自定义$sum累加器,以便在求和的同时对每个字段值进行一定的处理。如子字符串或正则表达式处理等。

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    .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" } } }
    ])
    

    【讨论】:

      猜你喜欢
      • 2022-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-02-13
      • 1970-01-01
      相关资源
      最近更新 更多