目前,我只有fullname
存储在MongoDB的User
集合中。我想运行一个分割名字和姓氏的报告,所以现在我试图运行聚合并在找到空格时拆分字符串。
这是我现在所拥有的,但我想根据找到空白的位置用一个变量替换硬编码的结束位置。这在汇总管道中是否可行?
db.users.aggregate([{
$project : {
fullname:{ $toUpper:"$fullname" },
first: { $substr: [ "$fullname", 0, 2 ]}, _id:0 }
}, { $sort : { fullname : 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"可能",它的输出是非常自以为是,并不是真正用于这样的操作。