1

MongoDB的聚合似乎相当复杂,如果有人能给我一个好的、简单的例子让我牢牢掌握基础知识,我将不胜感激。

考虑一个包含包含文件名和文件大小的文档的集合。

如何获得所有文件大小的总和?

此外,如何获得仅以字母“a”开头的文件的总和?

4

1 回答 1

3

这是使用异步 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,罗布。

于 2013-03-04T05:28:15.997 回答