1. 概要

このチュートリアルでは、MongoDBJavaドライバーを使用してMongoDBAggregationフレームワークについて詳しく説明します。

まず、集約の概念的な意味を確認してから、データセットを設定します。 最後に、AggregatesBuilderを使用したさまざまな集計手法の動作を確認します。

2. アグリゲーションとは何ですか?

AggregationsはMongoDBで使用され、データを分析し、そこから意味のある情報を導き出します

これらは通常、さまざまなステージで実行され、ステージはパイプラインを形成します。つまり、あるステージの出力が次のステージへの入力として渡されます。

最も一般的に使用されるステージは、次のように要約できます。

ステージ SQLと同等 説明
 事業 選択する 必要なフィールドのみを選択し、派生フィールドを計算してコレクションに追加するためにも使用できます
 マッチ どこ 指定された基準に従ってコレクションをフィルタリングします
 グループ GROUP BY 指定された基準に従って入力を収集します(例: count、sum)個別のグループごとにドキュメントを返します
 選別 注文者 結果を特定のフィールドの昇順または降順で並べ替えます
 カウント カウント コレクションに含まれるドキュメントをカウントします
 制限 制限 コレクション全体を返すのではなく、結果を指定された数のドキュメントに制限します
 アウト NEW_TABLEに選択 結果を名前付きコレクションに書き込みます。 この段階は、パイプラインの最後としてのみ受け入れられます

各集約ステージのSQLEquivalent は、SQLの世界で前述の操作が何を意味するかを理解するために、上記に含まれています。

これらすべてのステージのJavaコードサンプルをまもなく見ていきます。 しかしその前に、データベースが必要です。

3. データベースの設定

3.1. データセット

データベース関連のことを学ぶための最初のそして最も重要な要件は、データセット自体です!

このチュートリアルでは、公開されているRESTful APIエンドポイントを使用して、世界のすべての国に関する包括的な情報を提供します。 このAPIは、便利なJSON形式で国の多くのデータポイントを提供します。 分析で使用するフィールドのいくつかは次のとおりです。

  • name –国の名前。 たとえば、アメリカ合衆国
  • alpha3Code –国名のショートコード。 たとえば、 IND (インドの場合)
  • region –国が属する地域。 たとえば、 Europe
  • area –国の地理的領域
  • languages –配列形式の国の公用語。 たとえば、英語
  • borders –近隣諸国のalpha3Codeの配列

次に、このデータをMongoDBデータベースのコレクションに変換する方法を見てみましょう。

3.2. MongoDBへのインポート

まず、 APIエンドポイントをヒットしてすべての国を取得し、応答をローカルでJSONファイルに保存する必要があります。 次のステップは、mongoimportコマンドを使用してMongoDBにインポートすることです。

mongoimport.exe --db <db_name> --collection <collection_name> --file <path_to_file> --jsonArray

インポートが成功すると、250のドキュメントを含むコレクションが得られます。

4. Javaでの集約サンプル

基盤がカバーされたので、に取り掛かり、すべての国のデータからいくつかの意味のある洞察を導き出します。 この目的のために、いくつかのJUnitテストを使用します。

ただし、その前に、データベースに接続する必要があります。

@BeforeClass
public static void setUpDB() throws IOException {
    mongoClient = MongoClients.create();
    database = mongoClient.getDatabase(DATABASE);
    collection = database.getCollection(COLLECTION);
}

以下のすべての例では、MongoDBJavaドライバーによって提供されるAggregatesヘルパークラスを使用します。

スニペットを読みやすくするために、静的インポートを追加できます。

import static com.mongodb.client.model.Aggregates.*;

4.1. 一致およびカウント

まず、簡単なことから始めましょう。 以前、データセットには言語に関する情報が含まれていることを説明しました。

ここで、英語が公用語である世界の国の数を確認したいとします。

@Test
public void givenCountryCollection_whenEnglishSpeakingCountriesCounted_thenNinetyOne() {
    Document englishSpeakingCountries = collection.aggregate(Arrays.asList(
      match(Filters.eq("languages.name", "English")),
      count())).first();
    
    assertEquals(91, englishSpeakingCountries.get("count"));
}

ここでは、集計パイプラインでmatchとcountの2つのステージを使用しています。

まず、コレクションを除外して、言語フィールドに英語を含むドキュメントのみを照合します。 これらのドキュメントは、次のステージ count。の入力となる一時的または中間的なコレクションとして想像できます。これは、前のステージのドキュメントの数をカウントします。

このサンプルで注意すべきもう1つのポイントは、メソッドfirstの使用です。 最後のステージの出力countが単一のレコードになることがわかっているので、これは、結果として得られる唯一のドキュメントを抽出するための保証された方法です。

4.2. group sum を使用)および sort

この例では、私たちの目的は最大数の国を含む地理的地域を見つけることです

@Test
public void givenCountryCollection_whenCountedRegionWise_thenMaxInAfrica() {
    Document maxCountriedRegion = collection.aggregate(Arrays.asList(
      group("$region", Accumulators.sum("tally", 1)),
      sort(Sorts.descending("tally")))).first();
    
    assertTrue(maxCountriedRegion.containsValue("Africa"));
}

明らかなように、ここでの目的を達成するためにグループとソートを使用しています

まず、発生の sum を変数tallyに累積することにより、各地域の国の数を収集します。これにより、それぞれに2つのフィールドを含むドキュメントの中間コレクションが得られます。地域とその中の国の集計。  次に、降順で並べ替え、最初のドキュメントを抽出して、国が最大の地域を示します。

4.3. sort、 limit、および out

次に、ソート、制限、およびアウトを使用して、地域ごとに7つの最大の国を抽出し、それらを新しいコレクションに書き込みます。

@Test
public void givenCountryCollection_whenAreaSortedDescending_thenSuccess() {
    collection.aggregate(Arrays.asList(
      sort(Sorts.descending("area")), 
      limit(7),
      out("largest_seven"))).toCollection();

    MongoCollection<Document> largestSeven = database.getCollection("largest_seven");

    assertEquals(7, largestSeven.countDocuments());

    Document usa = largestSeven.find(Filters.eq("alpha3Code", "USA")).first();

    assertNotNull(usa);
}

ここでは、最初に指定されたコレクションを areaの降順で並べ替えました。次に、 Aggregates#limit メソッドを使用して、結果を7つのドキュメントのみに制限しました。 最後に、 outステージを使用して、このデータをlargest_sevenという新しいコレクションに逆シリアル化しました。 このコレクションは、他のコレクションと同じように使用できるようになりました。たとえば、USAが含まれている場合はfindに使用できます。

4.4. プロジェクト、グループ(最大)、一致

最後のサンプルでは、もっとトリッキーなことを試してみましょう。 各国が他の国と共有している国境の数と、そのような最大数を調べる必要があるとします。

これでデータセットに、 国境配列リストであるフィールド alpha3Code s国のすべての国境を接する国のために、 しかし、私たちに直接カウントを与えるフィールドはありません。 したがって、次の数を導出する必要があります国境を接する国を使用して事業

@Test
public void givenCountryCollection_whenNeighborsCalculated_thenMaxIsFifteenInChina() {
    Bson borderingCountriesCollection = project(Projections.fields(Projections.excludeId(), 
      Projections.include("name"), Projections.computed("borderingCountries", 
        Projections.computed("$size", "$borders"))));
    
    int maxValue = collection.aggregate(Arrays.asList(borderingCountriesCollection, 
      group(null, Accumulators.max("max", "$borderingCountries"))))
      .first().getInteger("max");

    assertEquals(15, maxValue);

    Document maxNeighboredCountry = collection.aggregate(Arrays.asList(borderingCountriesCollection,
      match(Filters.eq("borderingCountries", maxValue)))).first();
       
    assertTrue(maxNeighboredCountry.containsValue("China"));
}

その後、前に見たように、投影されたコレクションを group して、borderingCountriesmax値を見つけます。 ここで指摘することの1つは、 maxアキュムレータは、最大値を含む Document 全体ではなく、数値として最大値を提供することです。 さらに操作を実行する場合は、 match を実行して、目的のDocumentを除外する必要があります。

5. 結論

この記事では、 MongoDBアグリゲーションとは何か、およびサンプルデータセットを使用してJavaでそれらを適用する方法について説明しました。

概念の基本的な理解を形成するために、さまざまな集計段階を説明するために4つのサンプルを使用しました。 このフレームワークが提供するデータ分析には多くの可能性があり、さらに調査することができます

詳細については、 Spring Data MongoDB が、Javaでプロジェクションとアグリゲーションを処理するための代替方法を提供します。

いつものように、ソースコードはGitHubから入手できます。