1

MongoDB のアグリゲーションはかなり複雑に思えますが、基本をしっかりと理解するために、誰かが良い、簡単な例を教えてくれれば幸いです。

ファイル名とファイル サイズを含むドキュメントを含むコレクションを考えてみてください。

すべてのファイルのサイズの合計を取得するにはどうすればよいですか?

さらに、文字「a」で始まるファイルのみの合計を取得するにはどうすればよいですか?

4

1 に答える 1

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);
        }
    }

}

シェルでどのように見えるかを確認できるように、プログラムで集計パイプラインをダンプします。出力を見てみましょう。

pipeline : [
  {
    '$group' : {
      '_id' : 'sum',
      total : { '$sum' : '$size' },
      count : { '$sum' : 1 }
    }
  }
]

これは最初のクエリのパイプラインで、ファイルのサイズを合計します。パイプラインの唯一のステージとして「$group」演算子を使用します。定数 ID ('_id' : 'sum') を割り当てて、すべてのドキュメントを 1 つの結果ドキュメントにグループ化します。次に、total 行と count 行が各ドキュメントの size フィールドを合計し、ドキュメント数を返します。この集計の結果は次のようになります。

{
  '_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' が適しています。(2 つの $regex ドキュメントは、ドライバーが JSON をエンコードする方法の副作用です。最初の $regex は「一致」演算子であり、2 番目は正規表現を表す MongoDB 拡張を表します。)

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

そして、結果は正しく見えます。26 ドキュメントと合計 260。

HTH、ロブ。

于 2013-03-04T05:28:15.997 に答える