データ]

  • リンク:/tag/mongodb/[MongoDB]


1概要

Spring Data MongoDBは、MongoDBのネイティブクエリ言語に対する単純で高度な抽象化を提供します。この記事では、Projection and Aggregationフレームワークのサポートについて調べます。

このトピックが初めての場合は、紹介記事のリンク/spring-data-mongodb-tutorial[Spring Data MongoDBの紹介]を参照してください。


2投影

MongoDBでは、Projectionはデータベースからドキュメントの必須フィールドのみを取得する方法です。これにより、データベースサーバーからクライアントに転送する必要があるデータ量が減り、パフォーマンスが向上します。

Spring Data MongDBでは、

MongoTemplate



MongoRepository.

の両方で射影を使用できます。

先に進む前に、使用するデータモデルを見てみましょう。

@Document
public class User {
    @Id
    private String id;
    private String name;
    private Integer age;

   //standard getters and setters
}


2.1.

MongoTemplate


を使用した射影


Field

クラスの

include()

メソッドと

exclude()

メソッドは、それぞれフィールドの包含と除外に使用されます。

Query query = new Query();
query.fields().include("name").exclude("id");
List<User> john = mongoTemplate.find(query, User.class);

これらのメソッドを組み合わせて、複数のフィールドを含めるか除外することができます。

@ Id

(データベースでは

__id

)とマークされたフィールドは、明示的に除外されていない限り、常にフェッチされます。

レコードが射影でフェッチされた場合、除外されたフィールドはモデルクラスインスタンスでは

null

です。フィールドがプリミティブ型またはそれらのラッパークラスの場合、除外されたフィールドの値はプリミティブ型のデフォルト値です。

たとえば、

String



null



int

/

Integer



0



boolean

/

Boolean



false

になります。

したがって、上記の例では、

name

フィールドは

John



id



null



age



0.

になります。


2.2.

MongoRepository


を使用した予測

MongoRepositoriesを使用している間は、

@ Query

アノテーションの

fields

をJSON形式で定義できます。

@Query(value="{}", fields="{name : 1, __id : 0}")
List<User> findNameAndExcludeId();

結果はMongoTemplateを使用した場合と同じになります。

value =” \ {}”

はフィルタがないことを示し、したがってすべてのドキュメントが取得されます。


3

集計


MongoDBの集計は、データを処理して計算結果を返すように構築されています。データは段階的に処理され、ある段階の出力は次の段階への入力として提供されます。変換を適用し、段階的にデータを計算するこの機能により、集計は分析のための非常に強力なツールになります。

Spring Data MongoDBは、集約クエリをラップする3つのクラス

Aggregation

、個々のパイプラインステージをラップする

AggregationOperation

、および集約によって生成された結果のコンテナである

AggregationResults

を使用して、ネイティブ集約クエリの抽象化を提供します。

集約を実行するには、まず

Aggregation

クラスの静的ビルダーメソッドを使用して集約パイプラインを作成し、次に

newAggregation()

メソッドを使用して

Aggregation

のインスタンスを作成し、最後に

MongoTemplate

を使用して集約を実行します。

MatchOperation matchStage = Aggregation.match(new Criteria("foo").is("bar"));
ProjectionOperation projectStage = Aggregation.project("foo", "bar.baz");

Aggregation aggregation
  = Aggregation.newAggregation(matchStage, projectStage);

AggregationResults<OutType> output
  = mongoTemplate.aggregate(aggregation, "foobar", OutType.class);


MatchOperation



ProjectionOperation

の両方が

AggregationOperation

を実装していることに注意してください。他の集約パイプラインにも同様の実装があります。

OutType

は、予想される出力のデータモデルです。

ここでは、主要な集約パイプラインと演算子について説明するために、いくつかの例とその説明を見ていきます。

この記事で使用する予定のデータセットには、米国内のすべての郵便番号に関する詳細がリストされています。これは、http://media.mongodb.org/zips.json[MonoDB]からダウンロードできます。


test

データベースの

zips

というコレクションにインポートした後のサンプル文書を見てみましょう。

{
    "__id" : "01001",
    "city" : "AGAWAM",
    "loc" :[        -72.622739,
        42.070206
   ],
    "pop" : 15338,
    "state" : "MA"
}

簡単にし、コードを簡潔にするために、次のコードスニペットでは、

Aggregation

クラスのすべての

static

メソッドが静的にインポートされると想定します。


3.1. 人口の多い順で人口が1000万人を超える国をすべての国から探す

ここでは3つのパイプラインがあります。

  1. すべての郵便番号の人口を合計する

    $ group

    ステージ

  2. 1000万人以上の人口を持つ州を除外するための

    $ match

    ステージ

  3. すべての文書を降順にソートする

    $ sort

    ステージ

人口

期待される出力には、州としてのフィールド

__id

と、州の総人口を含むフィールド

statePop

があります。このためのデータモデルを作成して、集計を実行しましょう。

public class StatePoulation {

    @Id
    private String state;
    private Integer statePop;

   //standard getters and setters
}


@ Id

アノテーションはモデルの出力から

state



__id

フィールドをマッピングします。

GroupOperation groupByStateAndSumPop = group("state")
  .sum("pop").as("statePop");
MatchOperation filterStates = match(new Criteria("statePop").gt(10000000));
SortOperation sortByPopDesc = sort(new Sort(Direction.DESC, "statePop"));

Aggregation aggregation = newAggregation(
  groupByStateAndSumPop, filterStates, sortByPopDesc);
AggregationResults<StatePopulation> result = mongoTemplate.aggregate(
  aggregation, "zips", StatePopulation.class);


AggregationResults

クラスは

Iterable

を実装しているため、それを反復処理して結果を出力できます。

出力データモデルがわからない場合は、標準のMongoDBクラス

Document

を使用できます。


3.2. 平均的な人口で最小の状態を取得する

この問題では、4つの段階が必要になります。

  1. 各都市の総人口を合計するための

    $ group

  2. 各州の平均人口を計算するための

    $ group

  3. 都市の平均人口で州を並べ替える

昇順
。平均都市人口が最も少ない最初の州を取得するには

$ limit

必ずしも必要というわけではありませんが、

StatePopulation

データモデルに従って、ドキュメントを再フォーマットするために


project __ステージを追加します。

GroupOperation sumTotalCityPop = group("state", "city")
  .sum("pop").as("cityPop");
GroupOperation averageStatePop = group("__id.state")
  .avg("cityPop").as("avgCityPop");
SortOperation sortByAvgPopAsc = sort(new Sort(Direction.ASC, "avgCityPop"));
LimitOperation limitToOnlyFirstDoc = limit(1);
ProjectionOperation projectToMatchModel = project()
  .andExpression("__id").as("state")
  .andExpression("avgCityPop").as("statePop");

Aggregation aggregation = newAggregation(
  sumTotalCityPop, averageStatePop, sortByAvgPopAsc,
  limitToOnlyFirstDoc, projectToMatchModel);

AggregationResults<StatePopulation> result = mongoTemplate
  .aggregate(aggregation, "zips", StatePopulation.class);
StatePopulation smallestState = result.getUniqueMappedResult();

この例では、最後の段階で出力文書の数を1に制限しているため、結果には1つの文書しかないことがすでにわかっています。そのため、

getUniqueMappedResult()

を呼び出して、必要な

StatePopulation

インスタンスを取得できます。

注目すべきもう1つのことは、

__ id

をstateにマップするために

@ Id

アノテーションに頼るのではなく、投影段階で明示的に行ったことです。


3.3. 最大郵便番号と最小郵便番号で州を取得する

この例では、3つの段階が必要です。

  1. 各州の郵便番号の数を数える

    $ group

  2. 郵便番号の数で州を並べ替えるための

    $ sort


  3. $ first

    を使用して最大および最小の郵便番号で州を検索するには

    $ group



$ last

演算子

GroupOperation sumZips = group("state").count().as("zipCount");
SortOperation sortByCount = sort(Direction.ASC, "zipCount");
GroupOperation groupFirstAndLast = group().first("__id").as("minZipState")
  .first("zipCount").as("minZipCount").last("__id").as("maxZipState")
  .last("zipCount").as("maxZipCount");

Aggregation aggregation = newAggregation(sumZips, sortByCount, groupFirstAndLast);

AggregationResults<Document> result = mongoTemplate
  .aggregate(aggregation, "zips", Document.class);
Document document= result.getUniqueMappedResult();

ここでは、モデルは使用していませんが、MongoDBドライバーで既に提供されている

ドキュメント

を使用しました。


4結論

この記事では、Spring Data MongoDBの射影を使用して、MongoDBでドキュメントの指定されたフィールドを取得する方法を学びました。

また、Spring DataでのMongoDB集計フレームワークのサポートについても学びました。グループ化、プロジェクト化、ソート、制限、およびマッチングという主要な集約フェーズについて説明し、その実際的なアプリケーションの例をいくつか調べました。完全なソースコードはhttps://github.com/eugenp/tutorials/tree/master/persistence-modules/spring-data-mongodb[GitHubで入手可能]です。