通过拆分字段值来重塑文档

时间:2016-05-04 19:24:36

标签: javascript regex mongodb mongodb-query aggregation-framework

假设我们有一组原始数据:

{ "person": "David, age 102"}
{ "person": "Max, age 8" }

我们想将该集合转换为:

{ "age": 102 }
{ "age": 8 }

仅使用mongo(d)引擎。 (如果所有人名或年龄都有相同的长度,$ substr可以完成这项工作,)有可能吗?

假设正则表达式是微不足道的/ \ d + /

1 个答案:

答案 0 :(得分:3)

MongoDB版本3.4中的最佳方式。

这个版本的mongod提供了$split运算符,当然,它将字符串拆分为here

然后,我们使用$let变量运算符将新计算的值分配给变量。然后可以在 in 表达式中使用新值来返回" name"和#34;年龄"值使用$arrayElemAt运算符返回指定索引处的元素;第一个元素为0,最后一个元素为-1

请注意,在 in 表达式中,我们需要拆分最后一个元素,以便返回整数字符串。

最后,我们需要迭代Cursor对象,并使用NumberparseInt将整数字符串转换为数字,并使用批量操作和bulkWrite()方法$set这些字段的值,以实现最高效率。

let requests = [];
db.coll.aggregate(
    [
        { "$project": {  
            "person": { 
                "$let": { 
                    "vars": { 
                        "infos":  { "$split": [ "$person", "," ] } 
                    }, 
                    "in": { 
                        "name": { "$arrayElemAt": [ "$$infos", 0 ] }, 
                        "age": { 
                            "$arrayElemAt": [ 
                                { "$split": [ 
                                    { "$arrayElemAt": [ "$$infos", -1 ] }, 
                                    " " 
                                ]}, 
                                -1 
                            ] 
                        } 
                    } 
                } 
            }  
        }}
    ] 
).forEach(document => { 
    requests.push({ 
        "updateOne": { 
            "filter": { "_id": document._id }, 
            "update": { 
                "$set": { 
                    "name": document.person.name, 
                    "age": Number(document.person.age) 
                },
                "$unset": { "person": " " }
            } 
        } 
    }); 
    if ( requests.length === 500 ) { 
        // Execute per 500 ops and re-init
        db.coll.bulkWrite(requests); 
        requests = []; 
    }} 
);

 // Clean up queues
if(requests.length > 0) {
    db.coll.bulkWrite(requests);
}

MongoDB 3.2或更新版本。

MongoDB 3.2弃用旧的Bulk() API及其关联的methods并提供bulkWrite()方法,但它不提供$split运算符,因此唯一的选择我们这里使用mapReduce()方法转换我们的数据,然后使用批量操作更新集合。

var mapFunction = function() { 
    var person = {}, 
    infos = this.person.split(/[,\s]+/); 
    person["name"] = infos[0]; 
    person["age"] = infos[2]; 
    emit(this._id, person); 
};

var results = db.coll.mapReduce(
    mapFunction, 
    function(key, val) {}, 
    { "out": { "inline": 1 } }
)["results"];

results.forEach(document => { 
    requests.push({ 
        "updateOne": { 
            "filter": { "_id": document._id }, 
            "update": { 
                "$set": { 
                    "name": document.value.name, 
                    "age": Number(document.value.age) 
                }, 
                "$unset": { "person": " " }
            } 
        } 
    }); 
    if ( requests.length === 500 ) { 
        // Execute per 500 operations and re-init
        db.coll.bulkWrite(requests); 
        requests = []; 
    }} 
);

// Clean up queues
if(requests.length > 0) {
    db.coll.bulkWrite(requests);
}

MongoDB版本2.6或3.0。

我们需要使用现已弃用的Bulk API

var bulkOp = db.coll.initializeUnorderedBulkOp();
var count = 0;

results.forEach(function(document) { 
    bulkOp.find({ "_id": document._id}).updateOne(
        { 
            "$set": { 
                "name": document.value.name, 
                "age": Number(document.value.age)
            },
            "$unset": { "person": " " }
        }
    );
    count++;
    if (count === 500 ) {
        // Execute per 500 operations and re-init
        bulkOp.execute();
        bulkOp = db.coll.initializeUnorderedBulkOp();
    }
});

// clean up queues
if (count > 0 ) {
    bulkOp.execute();
}