在MongoDB聚合期间拆分字符串



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

这是我现在所拥有的,但我想根据空白的位置用一个变量来替换硬编码的结束位置。这在聚合管道中可能吗?

db.users.aggregate([{ 
    $project : {
        fullname:{ $toUpper:"$fullname" },
        first: { $substr: [ "$fullname", 0, 2 ]}, _id:0 }
    }, { $sort : { fullname : 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"可以",但它的输出非常有主见,并不是真正用于此类操作。

相关内容

  • 没有找到相关文章

最新更新