MongoDB Aggregation,我如何获得字段的总和?

时间:2013-03-04 04:29:16

标签: mongodb

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

想想包含包含文件名和文件大小的文档的集合。

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

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

1 个答案:

答案 0 :(得分:3)

以下是使用Asynchronous Java Driver的两个查询的示例程序:

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之前在管道中添加一个步骤来过滤或$匹配文档的子集。在这种情况下,正则表达式'^ a'适合账单。 (双$ regex文档是驱动程序编码JSON方式的副作用。第一个$ regex是“匹配”运算符,第二个表示MongoDB扩展来表示正则表达式。)

{
  '_id' : 'sum',
  total : 260,
  count : 26
}

结果看起来正确。 26份文件和260份文件。

HTH, 罗布。