考虑以下示例:
db.article.aggregate(
{ $group : {
_id : "$author",
docsPerAuthor : { $sum : 1 },
viewsPerAuthor : { $sum : "$pageViews" }
}}
);
这个分组由作者字段组成,并计算两个字段。
我有$ author = FirstName_LastName的值。 现在不是按$ author分组,而是希望由共享相同LastName的所有作者进行分组。
我试过$ regex按'_'
之后的所有匹配字符串进行分组$author.match(/_[a-zA-Z0-9]+$/)
db.article.aggregate(
{ $group : {
_id : "$author".match(/_[a-zA-Z0-9]+$/),
docsPerAuthor : { $sum : 1 },
viewsPerAuthor : { $sum : "$pageViews" }
}}
);
also tried the following:
db.article.aggregate(
{ $group : {
_id : {$author: {$regex: /_[a-zA-Z0-9]+$/}},
docsPerAuthor : { $sum : 1 },
viewsPerAuthor : { $sum : "$pageViews" }
}}
);
答案 0 :(得分:6)
实际上没有提供此类功能的方法,或者找不到包含它的相应版本。我认为这不适用于$ regexp:http://docs.mongodb.org/manual/reference/operator/regex/它只适用于模式匹配。
jira中有一项改进请求:https://jira.mongodb.org/browse/SERVER-6773
处于未解决状态。 BUT
在github中我发现了这个问题:https://github.com/mongodb/mongo/pull/336
如果您检查此提交:https://github.com/nleite/mongo/commit/2dd175a5acda86aaad61f5eb9dab83ee19915709
它或多或少地包含了您可能拥有的方法。我并没有真正理解这种改进的状态:在2.2.3中它没有用。
答案 1 :(得分:4)
使用mapReduce:它是聚合的一般形式。这是如何在mongo shell中继续: 定义地图功能
var mapFunction = function() {
var key = this.author.match(/_[a-zA-Z0-9]+$/)[0];
var nb_match_bar2 = 0;
if( this.bar.match(/bar2/g) ){
nb_match_bar2 = 1;
}
var value = {
docsPerAuthor: 1,
viewsPerAuthor: Array.sum(this.pageViews)
};
emit( key, value );
};
和reduce函数
var reduceFunction = function(key, values) {
var reducedObject = {
_id: key,
docsPerAuthor: 0,
viewsPerAuthor: 0
};
values.forEach( function(value) {
reducedObject.docsPerAuthor += value.docsPerAuthor;
reducedObject.viewsPerAuthor += value.viewsPerAuthor;
}
);
return reducedObject;
};
运行mapReduce并将结果保存在map_reduce_result
中>db.st.mapReduce(mapFunction, reduceFunction, {out:'map_reduce_result'})
查询map_reduce_result以获得结果
>db.map_reduce_result.find()
答案 2 :(得分:3)
聚合框架的一种可能的解决方法是使用$ project来计算作者名称。但是,它很脏,因为您需要手动循环使用不同的名字大小:
在这里,我们将字段名称计算为'_'字符后面的子字符串,尝试每个可能的位置(这就是为什么有一个$ cond链),并在第一个返回整个$ author时回退名字太长了:
http://mongotry.herokuapp.com/#?bookmarkId=52fb5f24a0378802003b4c68
[
{
"$project": {
"author": 1,
"pageViews": 1,
"name": {
"$cond": [
{
"$eq": [
{
"$substr": [
"$author",
0,
1
]
},
"_"
]
},
{
"$substr": [
"$author",
1,
999
]
},
{
"$cond": [
{
"$eq": [
{
"$substr": [
"$author",
1,
1
]
},
"_"
]
},
{
"$substr": [
"$author",
2,
999
]
},
{
"$cond": [
{
"$eq": [
{
"$substr": [
"$author",
2,
1
]
},
"_"
]
},
{
"$substr": [
"$author",
3,
999
]
},
{
"$cond": [
{
"$eq": [
{
"$substr": [
"$author",
3,
1
]
},
"_"
]
},
{
"$substr": [
"$author",
4,
999
]
},
{
"$cond": [
{
"$eq": [
{
"$substr": [
"$author",
4,
1
]
},
"_"
]
},
{
"$substr": [
"$author",
5,
999
]
},
"$author"
]
}
]
}
]
}
]
}
]
}
}
},
{
"$group": {
"_id": "$name",
"viewsPerAuthor": {
"$sum": "$pageViews"
}
}
}
]
答案 3 :(得分:0)
$group
与$addFields
和$arrayElemAt
结合使用对我而言(版本≥3.4)。
假设我们在数据库faculty
的集合school
中有以下数据:
{ "_id" : ObjectId("5ed5a59b1febc4c796a88e80"), "name" : "Harry_Potter" }
{ "_id" : ObjectId("5ed5a60e1febc4c796a88e81"), "name" : "Edison_Potter" }
{ "_id" : ObjectId("5ed5a6231febc4c796a88e82"), "name" : "Jack_Potter" }
{ "_id" : ObjectId("5ed5a62f1febc4c796a88e83"), "name" : "Alice_Walker" }
{ "_id" : ObjectId("5ed5a65f1febc4c796a88e84"), "name" : "Bob_Walker" }
{ "_id" : ObjectId("5ed5a6731febc4c796a88e85"), "name" : "Will_Smith" }
以下可以按姓氏将每个文档分组:
db.faculty.aggregate([
{
$addFields: {
lastName: {
$arrayElemAt: [ { $split: ["$name", "_"] }, 1 ]
}
}
},
{
$group: {
_id: "$lastName",
count: {$sum: 1}
}
}
])
运行结果为:
{ "_id" : "Potter", "count" : 3 }
{ "_id" : "Walker", "count" : 2 }
{ "_id" : "Smith", "count" : 1 }
我使用的技巧是添加一个名为lastName
的字段。根据{{1}}字段的内容,name
可以将其拆分为一个数组。姓氏在索引1上,姓氏在索引0上。
参考