【问题标题】:Split a string during MongoDB aggregate在 MongoDB 聚合期间拆分字符串
【发布时间】:2016-02-08 21:52:03
【问题描述】:

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

这就是我现在所拥有的,但我想用一个基于空格所在位置的变量替换硬编码的结束位置。这在聚合管道中是否可行?

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

【问题讨论】:

    标签: mongodb mapreduce mongodb-query aggregation-framework


    【解决方案1】:

    聚合框架没有任何运算符来根据匹配的字符或任何类似的东西执行“拆分”。只有$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 “可以”,但它的输出是非常固执的,并不是真正用于这样的操作。

    【讨论】:

    • @user3100115 纯粹从问题编号来看,它是一个“非常古老”的开放式 JIRA。类似于聚合“正则表达式”请求(这也是旧的),它主要是关于运算符语法而不是破坏现有的东西。无论如何,通过使用单独的属性来构造文档中的数据,可以更好地解决大多数用例。这就是这里主要介绍的情况。
    • 感谢@Blakes 七。我应该澄清排序并不像拆分名称那么重要。从长远来看,我们计划只存储名字和姓氏,但由于我正在处理现有的数据库,所以我喜欢 $set 建议,因为这是我的 1 次工作不太关心性能。
    • 3.4 版现在有 split 和 indexOfBytes 聚合运算符:docs.mongodb.com/manual/release-notes/3.4
    猜你喜欢
    • 1970-01-01
    • 2015-10-20
    • 2021-11-10
    • 1970-01-01
    • 2020-09-19
    • 2022-08-16
    • 1970-01-01
    • 2023-04-02
    • 1970-01-01
    相关资源
    最近更新 更多