在MongoDB聚合期间拆分字符串

时间:2015-11-07 23:24:27

标签: mongodb mapreduce mongodb-query aggregation-framework

目前,我只有fullname存储在MongoDB的User集合中。我想运行一个分割名字和姓氏的报告,所以现在我试图运行聚合并在找到空格时拆分字符串。

这是我现在所拥有的,但我想根据找到空白的位置用一个变量替换硬编码的结束位置。这在汇总管道中是否可行?

db.users.aggregate([{ 
    $project : {
        fullname:{ $toUpper:"$fullname" },
        first: { $substr: [ "$fullname", 0, 2 ]}, _id:0 }
    }, { $sort : { fullname : 1 }
}]);

1 个答案:

答案 0 :(得分:3)

聚合框架没有任何运算符来执行" split"基于匹配的角色或任何此类事物。只有$substr当然需要索引,并且没有运算符可以返回"索引"匹配的角色。

您可以使用mapReduce,它可以使用JavaScript .split(),但当然没有"排序阶段"在mapReduce中除主键之外的结果,在尝试应用reduce之前总是预先排序(这里不会应用所有唯一键):

db.users.mapReduce(
    function() {
        var lastName = this.fullname.split(/\s/).reverse()[0].toUpperCase();

        emit({ "lastName": lastName, "orig": this._id },this);
    },
    function(){},     // Never called on all unique
    { "out": { "inline": 1 } }
);

这基本上会在空格后提取姓氏,将其转换为大写并将其用作主键中的复合值,因此结果将按该键排序(请注意,您不能使用_id作为任何键密钥名称的一部分,或者它将按该字段排序。)

但是,如果你的真实情况是"排序",那么你最好以这种方式存储数据,从而为你提供直接值,无需计算即可进行排序:

var bulk = db.users.initializeOrderedBulkOp(),
    count = 0;

db.users.find().forEach(user) {
    bulk.find({ "_id": user._id }).updateOne({
        "$set": { "lastName": user.fullname.split(/\s/).reverse()[0].toUpperCase() }
    });
    count++;

    if ( count % 1000 == 0 ) {
        bulk.execute();
        bulk = db.users.initializeOrderedBulkOp();
    }
}  

if ( count % 1000 != 0 )
    bulk.execute();

然后使用固定字段,您只需运行排序:

db.users.find().sort({ "lastName": 1 });

这比尝试计算执行排序的值要快得多。

当然,如果排序不是目的而且只是用于演示,那么只需在客户端代码中执行拆分,这样做最有意义。聚合框架不能像这样重构数据,而mapReduce"可能",它的输出是非常自以为是,并不是真正用于这样的操作。