MongoDB的聚合似乎相当复杂,如果有人能给我一个好的、简单的例子让我牢牢掌握基础知识,我将不胜感激。
考虑一个包含包含文件名和文件大小的文档的集合。
如何获得所有文件大小的总和?
此外,如何获得仅以字母“a”开头的文件的总和?
MongoDB的聚合似乎相当复杂,如果有人能给我一个好的、简单的例子让我牢牢掌握基础知识,我将不胜感激。
考虑一个包含包含文件名和文件大小的文档的集合。
如何获得所有文件大小的总和?
此外,如何获得仅以字母“a”开头的文件的总和?
这是使用异步 Java 驱动程序的两个查询的示例程序:
package example;
import static com.allanbank.mongodb.builder.AggregationGroupField.set;
import static com.allanbank.mongodb.builder.AggregationGroupId.constantId;
import static com.allanbank.mongodb.builder.QueryBuilder.where;
import java.util.regex.Pattern;
import com.allanbank.mongodb.MongoClient;
import com.allanbank.mongodb.MongoCollection;
import com.allanbank.mongodb.MongoFactory;
import com.allanbank.mongodb.bson.Document;
import com.allanbank.mongodb.bson.builder.BuilderFactory;
import com.allanbank.mongodb.bson.builder.DocumentBuilder;
import com.allanbank.mongodb.bson.element.ArrayElement;
import com.allanbank.mongodb.builder.Aggregate;
public class FileSizeAggregation {
public static void main(String[] args) {
MongoClient client = MongoFactory
.createClient("mongodb://localhost:27017");
MongoCollection collection = client.getDatabase("test").getCollection(
"test");
collection.delete(BuilderFactory.start()); // Clear the collection.
// Create some documents.
DocumentBuilder doc = BuilderFactory.start();
for (char first = 'a'; first <= 'z'; ++first) {
for (char second = 'a'; second <= 'z'; ++second) {
doc.reset();
doc.add("name", new String(new char[] { first, second }));
doc.add("size", 10);
collection.insert(doc);
}
}
// Count all file "sizes".
Aggregate.Builder builder = new Aggregate.Builder();
builder.group(constantId("sum"),
set("total").sum("size"),
set("count").count());
System.out.println(new ArrayElement("pipeline", builder.build()
.getPipeline()));
Iterable<Document> docs = collection.aggregate(builder.build());
for (Document d : docs) {
System.out.println(d);
}
// Count all file sizes that start with "a"
builder.reset();
builder.match(where("name").matches(Pattern.compile("^a")));
builder.group(constantId("sum"),
set("total").sum("size"),
set("count").count());
System.out.println(new ArrayElement("pipeline", builder.build()
.getPipeline()));
docs = collection.aggregate(builder.build());
for (Document d : docs) {
System.out.println(d);
}
}
}
我让程序转储出聚合管道,这样你就可以看到它在 shell 中的样子。让我们看看输出。
pipeline : [
{
'$group' : {
'_id' : 'sum',
total : { '$sum' : '$size' },
count : { '$sum' : 1 }
}
}
]
这是第一个查询的管道,对文件的大小求和。我们使用“$group”运算符作为管道中的唯一阶段。我们分配一个常量 id ('_id' : 'sum') 以将所有文档分组到一个结果文档中。然后总行和计数行对每个文档中的大小字段求和并返回文档计数。此聚合的结果如下所示:
{
'_id' : 'sum',
total : 6760,
count : 676
}
676 个文件(26 * 26),因为每个文件是“10”,所以总数是 6760。看起来不错。下一个聚合!
这次我们只想总结文件名以字母“a”开头的文档。
pipeline : [
{
'$match' : {
name : { '$regex' : { $regex : '^a' } }
}
},
{
'$group' : {
'_id' : 'sum',
total : { '$sum' : '$size' },
count : { '$sum' : 1 }
}
}
]
唯一真正的变化是我们在 $group 之前在管道中添加了一个步骤来过滤或 $match 文档的子集。在这种情况下,正则表达式 '^a' 符合要求。(双 $regex 文档是驱动程序编码 JSON 方式的副作用。第一个 $regex 是“匹配”运算符,第二个表示 MongoDB 扩展以表示正则表达式。)
{
'_id' : 'sum',
total : 260,
count : 26
}
结果看起来不错。26 份文件,总共 260 份。
HTH,罗布。