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