Docs Menu
Docs Home
/ / /
Java Sync Driver
/

集計式演算子

項目一覧

  • Overview
  • 操作の使用方法
  • コンストラクター メソッド
  • 操作
  • 算術演算
  • 配列演算
  • ブール演算
  • 比較操作
  • 条件付き操作
  • 便利な操作
  • 変換操作
  • 日付操作
  • ドキュメント操作
  • マップ操作
  • string操作
  • 型チェック操作

このガイドでは、MongoDB Java ドライバーを使用して、集計パイプラインで使用する式を構築する方法を学習できます。 BSON ドキュメントではなく、検出可能なタイプセーフの Java メソッドを使用して式操作を実行できます。 これらのメソッドはスムーズなインターフェース パターンに従うため、集計操作を連鎖させて、より圧縮とより自然な読み取りの両方のコードを作成できます。

このガイドの操作では、 com.mongodb.client.model.mql のメソッドを使用します パッケージ。これらのメソッドは、ドライバーが MongoDB の配置を操作するメカニズムである Query API を慣用的に使用する方法を提供します。 Query API の詳細については、サーバー マニュアル ドキュメントを参照してください。

このガイドの例では、コードに次の静的インポートが含まれていることを前提としています。

import static com.mongodb.client.model.Aggregates.*;
import static com.mongodb.client.model.Accumulators.*
import static com.mongodb.client.model.Projections.*;
import static com.mongodb.client.model.Filters.*;
import static com.mongodb.client.model.mql.MqlValues.*;
import static java.util.Arrays.asList;

式内のドキュメント フィールドにアクセスするには、集計パイプラインによって処理されている現在のドキュメントを参照する必要があります。 このドキュメントを参照するには、 current()メソッドを使用します。 フィールドの値にアクセスするには、 getString()getDate()などの適切な型のメソッドを使用する必要があります。 フィールドに型を指定すると、ドライバーはその型と互換性のあるメソッドのみを提供するようになります。 次のコードは、 nameという string フィールドを参照する方法を示しています。

current().getString("name")

操作で値を指定するには、その値をof()コンストラクター メソッドに渡して、有効なタイプに変換します。 次のコードは、 1.0の値を参照する方法を示しています。

of(1.0)

操作を作成するには、フィールドまたは値の参照にメソッドを連鎖させます。 追加のメソッドを連鎖させることで、より複雑な操作を構築できます。

次の例では、医療機関を少なくとも 1 回訪問した新しいメキシコ語の検査を作成する操作を作成します。 この操作では、次のアクションが実行されます。

  • gt()メソッドを使用して、 visitDates配列のサイズが0より大きいかどうかを確認します

  • eq()メソッドを使用して、 stateフィールドの値が「ニューメキシコ」であるかどうかを確認します

and()メソッドはこれらの操作をリンクして、パイプライン ステージは両方の条件を満たすドキュメントのみと一致するようにします。

current()
.getArray("visitDates")
.size()
.gt(of(0))
.and(current()
.getString("state")
.eq(of("New Mexico")));

group()などの一部の集計ステージは操作を直接受け入れますが、他のステージでは最初にcomputed()expr()などのメソッドに操作を含めることが必要です。 TExpressionタイプの値を受け取るこれらのメソッドでは、特定の集計で式を使用できます。

集計パイプライン ステージを完了するには、集計ビルダのメソッドに式を含めます。 次のリストは、一般的な集計ビルダのメソッドに式を含める方法の例を示しています。

  • match(expr(<expression>))

  • project(fields(computed("<field name>", <expression>)))

  • group(<expression>)

これらのメソッドの詳細については、 集計ビルダを参照してください。

これらの例では、 asList()メソッドを使用して集計ステージのリストを作成しています。 このリストは、 MongoCollectionaggregate()メソッドに渡されます。

これらのコンストラクター メソッドを使用して、Java 集計式で使用する値を定義できます。

方式
説明
集計パイプラインによって処理されている現在のドキュメントを参照します。
集計パイプラインによって処理されている現在のドキュメントをマップ値として参照します。
指定されたプリミティブに対応するMqlValue型を返します。
指定されたプリミティブの配列に対応するMqlValue型の配列を返します。
エントリ値を返します。
空のマップ値を返します。
クエリ API に存在する null 値を返します。

重要

これらのメソッドのいずれかに値を指定すると、ドライバーはその値を文字通りそれを扱います。 たとえば、 of("$x")xという名前のフィールドではなく、string の値"$x"を表します。

これらのメソッドを使用する例については、「操作」のいずれかのセクションを参照してください。

次のセクションでは、ドライバーで使用可能な集計式操作に関する情報と例を提供します。 操作は、目的と機能によって分類されます。

各セクションには、ドライバーで使用できる集計メソッドと、クエリ API の対応する式演算子を説明する表があります。 メソッド名は API ドキュメントにリンクされ、集計パイプライン演算子名はサーバー マニュアル ドキュメントの説明と例にリンクされます。 各 Java メソッドは対応する Query API 式と実質的に同等ですが、期待されるパラメータと実装が異なる場合があります。

注意

ドライバーは、各例に提供されている Query API 式とは異なる Query API 式を生成します。 ただし、どちらの式でも生成される集計結果は同じになります。

重要

ドライバーは、クエリ API のすべての集計パイプライン演算子のメソッドを提供しません。 集計でサポートされていない操作を使用する必要がある場合は、BSON Document型を使用して式全体を定義する必要があります。 Document型の詳細については、ドキュメント を参照してください。

このセクションで説明されているメソッドを使用して、 MqlIntegerまたはMqlNumberタイプの値に対して算術演算を実行できます。

毎日の降順の降順の測定値(メートル単位)を含む特定の年の気象データがあるとします。 各月の平均降格量をミリ秒単位で求めます。

multiply()演算子は、 precipitationフィールドに25.4を乗算して値をミリ秒に変換します。 avg()アキュムレータ メソッドはavgPrecipMMフィールドとして平均を返します。 group()メソッドは、各ドキュメントのdateフィールドに指定された値を月別にグループ化します。

次のコードは、この集計のパイプラインを示しています。

var month = current().getDate("date").month(of("UTC"));
var precip = current().getInteger("precipitation");
asList(group(
month,
avg("avgPrecipMM", precip.multiply(25.4))
));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $group: {
_id: { $month: "$date" },
avgPrecipMM: {
$avg: { $multiply: ["$precipitation", 25.4] } }
} } ]

このセクションで説明されているメソッドを使用して、 MqlArrayの値に対して配列操作を実行できます。

映画のコレクションがあり、それぞれに今後の公開イベントのためにネストされたドキュメントの配列が含まれているとします。 ネストされた各ドキュメントには、劇場の総シート数を表す 配列が含まれています。配列の最初のエントリはプレミアム シートの数、2 番目のエントリは通常のシートの数です。 ネストされた各ドキュメントには、ライブタイムのためにすでに購入されたチケットの数も含まれています。 このコレクションのドキュメントは、次のようになります。

{
"_id": ...,
"movie": "Hamlet",
"showtimes": [
{
"date": "May 14, 2023, 12:00 PM",
"seats": [ 20, 80 ],
"ticketsBought": 100
},
{
"date": "May 20, 2023, 08:00 PM",
"seats": [ 10, 40 ],
"ticketsBought": 34
}]
}

filter()メソッドは、指定された述語に一致する結果のみを表示します。 この場合、述語はsum() を使用してシートの合計数を計算し、その値をticketsBought lt()とともに の数と比較します。project()メソッドは、これらのフィルタリングされた結果を新しいavailableShowtimes配列として保存します。

Tip

配列の値を特定の型として操作する場合は、 getArray()メソッドで取得する配列のタイプを指定する必要があります。

この例では、 seats配列にMqlDocument型の値が含まれていることを指定し、各配列エントリからネストされたフィールドを抽出できます。

次のコードは、この集計のパイプラインを示しています。

var showtimes = current().<MqlDocument>getArray("showtimes");
asList(project(fields(
computed("availableShowtimes", showtimes
.filter(showtime -> {
var seats = showtime.<MqlInteger>getArray("seats");
var totalSeats = seats.sum(n -> n);
var ticketsBought = showtime.getInteger("ticketsBought");
var isAvailable = ticketsBought.lt(totalSeats);
return isAvailable;
}))
)));

注意

読みやすくするために、前の例ではtotalSeats 変数とisAvailable 変数に中間値を割り当てています。これらの中間値を変数に抽出しない場合、コードは引き続き同等の結果を生成します。

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
availableShowtimes: {
$filter: {
input: "$showtimes",
as: "showtime",
cond: { $lt: [ "$$showtime.ticketsBought", { $sum: "$$showtime.seats" } ] }
} }
} } ]

このセクションで説明されているメソッドを使用して、 MqlBooleanタイプの値に対してブール値演算を実行できます。

Java メソッド
集計パイプライン演算子

非常に低い気象値または高い気象温度の読み取り値(華氏単位)を極端に分類するとします。

or()演算子は、 temperatureフィールドをlt()およびgt()の事前定義された値と比較して、温度が極端に高いかどうかをチェックします。 project()メソッドは、この結果をextremeTempフィールドに記録します。

次のコードは、この集計のパイプラインを示しています。

var temperature = current().getInteger("temperature");
asList(project(fields(
computed("extremeTemp", temperature
.lt(of(10))
.or(temperature.gt(of(95))))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
extremeTemp: { $or: [ { $lt: ["$temperature", 10] },
{ $gt: ["$temperature", 95] } ] }
} } ]

このセクションで説明されているメソッドを使用して、 MqlValue型の値に対して比較操作を実行できます。

Tip

cond()メソッドは Java の三項演算子に似ており、ブール値に基づく単純なブランチには使用する必要があります。 値型でパターン マッチングを実行したり、値に対してその他のチェックを実行したりするなど、より複雑な比較を行うには、 switchOn()メソッドを使用する必要があります。

次の例では、 locationフィールドの値が"California"であるすべてのドキュメントに一致するパイプラインを示しています。

var location = current().getString("location");
asList(match(expr(location.eq(of("California")))));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $match: { location: { $eq: "California" } } } ]

このセクションで説明されているメソッドを使用して、条件付き操作を実行できます。

メンバーシップ情報を持つカスタマーのコレクションがあるとします。 元々、カスタマーはメンバーかどうかのどちらかでした。 時間と共に、メンバーシップレベルが導入され、同じフィールドが使用されます。 このフィールドに保存される情報は数あるタイプのいずれかになる可能性があり、そのメンバーシップ レベルを示す標準化された値を作成する必要があります。

switchOn()メソッドは、各句を順番にチェックします。 値が 句で示される型と一致する場合、その句はメンバーシップ レベルに対応する string の値を決定します。 元の値が string の場合、それはメンバーシップ レベルを表し、その値が使用されます。 データ型がブール値の場合、メンバーシップ レベルのGoldまたはGuestのいずれかが返されます。 データ型が配列の場合、 配列内の最新のメンバーシップ レベルに一致する最新の string が返されます。 memberフィールドが不明なタイプの場合、 switchOn()メソッドはデフォルト値Guestを提供します。

次のコードは、この集計のパイプラインを示しています。

var member = current().getField("member");
asList(project(fields(
computed("membershipLevel",
member.switchOn(field -> field
.isString(s -> s)
.isBoolean(b -> b.cond(of("Gold"), of("Guest")))
.<MqlString>isArray(a -> a.last())
.defaults(d -> of("Guest"))))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
membershipLevel: {
$switch: {
branches: [
{ case: { $eq: [ { $type: "$member" }, "string" ] }, then: "$member" },
{ case: { $eq: [ { $type: "$member" }, "bool" ] }, then: { $cond: {
if: "$member",
then: "Gold",
else: "Guest" } } },
{ case: { $eq: [ { $type: "$member" }, "array" ] }, then: { $last: "$member" } }
],
default: "Guest" } }
} } ]

このセクションで説明されている方法を使用して、 MqlValueタイプの値にカスタム関数を適用できます。

読みやすさを向上させ、コードの再利用を可能にするには、冗長コードを静的メソッドに移動します。 ただし、Java で静的メソッドを直接連鎖させることはできません。 passTo()メソッドを使用すると、値をカスタム静的メソッドに連鎖させることができます。

Java メソッド
集計パイプライン演算子
対応する演算子がありません

いくつかのベンチマークに対してクラスがどのように実行されているかを判断したいとします。 各クラスの平均最終成績を見つけ、ベンチマーク値と比較します。

次のカスタム メソッドgradeAverage()は、ドキュメントの配列と、それらのドキュメント間で共有される整数フィールドの名前を受け取ります。 指定された配列内のすべてのドキュメントにわたるそのフィールドの平均を計算し、指定された配列内のすべての要素にわたるそのフィールドの平均を決定します。 evaluate() メソッドは、指定された値を指定された 2 つの範囲制限と比較し、値の比較方法に基づいて応答stringを生成します。

public static MqlNumber gradeAverage(MqlArray<MqlDocument> students, String fieldName) {
var sum = students.sum(student -> student.getInteger(fieldName));
var avg = sum.divide(students.size());
return avg;
}
public static MqlString evaluate(MqlNumber grade, MqlNumber cutoff1, MqlNumber cutoff2) {
var message = grade.switchOn(on -> on
.lte(cutoff1, g -> of("Needs improvement"))
.lte(cutoff2, g -> of("Meets expectations"))
.defaults(g -> of("Exceeds expectations")));
return message;
}

Tip

passTo()メソッドを使用する利点の 1 つは、カスタム メソッドを他の集計で再利用できることです。 gradeAverage()メソッドを使用すると、クラスだけでなく、エントリー年や地区などでフィルタリングされた学生グループの平均成績を見つけることができます。 evaluate()メソッドを使用して、個々の生徒のパフォーマンス、または学校全体または地区のパフォーマンスなどを評価できます。

passArrayTo()メソッドはすべての生徒を取得し、 gradeAverage()メソッドを使用して平均スコアを計算します。 次に、 passNumberTo()メソッドはevaluate()メソッドを使用してクラスのパフォーマンスを判断します。 この例では、 project()メソッドを使用して結果をevaluationフィールドとして保存します。

次のコードは、この集計のパイプラインを示しています。

var students = current().<MqlDocument>getArray("students");
asList(project(fields(
computed("evaluation", students
.passArrayTo(students -> gradeAverage(students, "finalGrade"))
.passNumberTo(grade -> evaluate(grade, of(70), of(85))))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
evaluation: { $switch: {
branches: [
{ case: { $lte: [ { $avg: "$students.finalGrade" }, 70 ] },
then: "Needs improvement"
},
{ case: { $lte: [ { $avg: "$students.finalGrade" }, 85 ] },
then: "Meets expectations"
}
],
default: "Exceeds expectations" } }
} } ]

このセクションで説明されているメソッドを使用して、変換操作を実行して特定のMqlValueタイプ間で変換できます。

Java メソッド
集計パイプライン演算子
対応する演算子がありません
対応する演算子がありません

廃止年を含む学生データのコレクションがあり、string として保存されるとします。 この値は 5 年間で、その値を新しい フィールドに保存します。

parseInteger()メソッドはgraduationYearを整数に変換し、 add()が同期年を計算できるようにします。 addFields()メソッドは、この結果を新しいreunionYearフィールドとして保存します。

次のコードは、この集計のパイプラインを示しています。

var graduationYear = current().getString("graduationYear");
asList(addFields(
new Field("reunionYear",
graduationYear
.parseInteger()
.add(5))
));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $addFields: {
reunionYear: {
$add: [ { $toInt: "$graduationYear" }, 5 ] }
} } ]

このセクションで説明されている方法を使用して、 MqlDate型の値に対して日付操作を実行できます。

パッケージの配達に関するデータがあり、 "America/New_York"タイムゾーン内のいずれかの月曜日に発生した配達を一致させたいとします。

deliveryDateフィールドに、 "2018-01-15T16:00:00Z"Jan 15, 2018, 12:00 PM ESTなどの有効な日付を表す string 値が含まれている場合は、 parseDate()メソッドを使用して string を日付型に変換できます。

dayOfWeek()メソッドは、曜日を決定し、 "America/New_York"パラメータに従って月曜日に基づいて数値に変換します。 eq()メソッドは、この値を2と比較します。これは指定されたタイムゾーン パラメータに基づく月曜日に対応します。

次のコードは、この集計のパイプラインを示しています。

var deliveryDate = current().getString("deliveryDate");
asList(match(expr(deliveryDate
.parseDate()
.dayOfWeek(of("America/New_York"))
.eq(of(2))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $match: {
$expr: {
$eq: [ {
$dayOfWeek: {
date: { $dateFromString: { dateString: "$deliveryDate" } },
timezone: "America/New_York" }},
2
] }
} } ]

このセクションで説明されている方法を使用して、 MqlDocument型の値に対してドキュメント操作を実行できます。

mailing.addressフィールドの下に子ドキュメントとしてアドレスを含むレガシーカスタマーデータのコレクションがあるとします。 現在ワシントン州に存在するカスタマーをすべて検索したいと考えています。 このコレクションのドキュメントは、次のようになります。

{
"_id": ...,
"customer.name": "Mary Kenneth Keller",
"mailing.address":
{
"street": "601 Mongo Drive",
"city": "Vasqueztown",
"state": "CO",
"zip": 27017
}
}

getDocument()メソッドはmailing.addressフィールドをドキュメントとして取得するため、ネストされたstateフィールドはgetString()メソッドで取得できます。 eq()メソッドは、 stateフィールドの値が"WA"であるかどうかを確認します。

次のコードは、この集計のパイプラインを示しています。

var address = current().getDocument("mailing.address");
asList(match(expr(address
.getString("state")
.eq(of("WA"))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[
{ $match: {
$expr: {
$eq: [{
$getField: {
input: { $getField: { input: "$$CURRENT", field: "mailing.address"}},
field: "state" }},
"WA" ]
}}}]

このセクションで説明されているメソッドを使用して、 MqlMapまたはMqlEntryのいずれかのタイプの値に対してマップ操作を実行できます。

Tip

データが日付やアイテム ID などの任意のキーを値にマッピングする場合は、データをマップとして表現する必要があります。

Java メソッド
集計パイプライン演算子
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません

たとえば、各ドキュメントが提供を担当する個々の商品を表す在庫データのコレクションがあるとします。 各ドキュメントには、すべての倉庫のマップと、アイテムの在庫内に現在存在するコピーの数である フィールドが含まれています。 すべての倉庫に存在する商品のコピー数の合計を判別したい場合があります。 このコレクションのドキュメントは、次のようになります。

{
"_id": ...,
"item": "notebook"
"warehouses": [
{ "Atlanta", 50 },
{ "Chicago", 0 },
{ "Portland", 120 },
{ "Dallas", 6 }
]
}

entries()メソッドは、 warehousesフィールドのマップエントリを配列として返します。 sum()メソッドは、 getValue()メソッドで検索された 配列の値に基づいて、アイテムの合計値を計算します。 この例では、 project()メソッドを使用して、結果を新しいtotalInventoryフィールドとして保存します。

次のコードは、この集計のパイプラインを示しています。

var warehouses = current().getMap("warehouses");
asList(project(fields(
computed("totalInventory", warehouses
.entries()
.sum(v -> v.getValue()))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
totalInventory: {
$sum: {
$getField: { $objectToArray: "$warehouses" },
} }
} } ]

このセクションで説明されているメソッドを使用して、 MqlStringタイプの値に対して string 操作を実行できます。

従業員の姓と従業員 ID から、会社の従業員の小文字のユーザー名を生成するとします。

append()メソッドはfirstName lastNameフィールドと フィールドを 1 つのユーザー名に結合し、toLower() メソッドはユーザー名全体を小文字にします。この例では、 project()メソッドを使用して、結果を新しいusernameフィールドとして保存します。

次のコードは、この集計のパイプラインを示しています。

var lastName = current().getString("lastName");
var employeeID = current().getString("employeeID");
asList(project(fields(
computed("username", lastName
.append(employeeID)
.toLower())
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
username: {
$toLower: { $concat: ["$lastName", "$employeeID"] } }
} } ]

このセクションで説明されている方法を使用して、 MqlValue型の値に対して型チェック操作を実行できます。

これらのメソッドはブール値を返しません。 代わりに、メソッドによって指定される型と一致するデフォルト値を指定します。 チェックされた値がメソッドの種類と一致する場合は、チェックされた値が返されます。 それ以外の場合は、指定されたデフォルト値が返されます。 データ型に基づいてブランチ ロジックをプログラムする場合は、 switchOn()を参照してください。

Java メソッド
集計パイプライン演算子
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません
対応する演算子がありません

評価データのコレクションがあるとします。 レビュー スキーマの初期バージョンでは、ユーザーはスター評価なしで負のレビューを送信できました。 スター評価のないこれらの否定的なレビューを、最小値が 1 スターになるように変換します。

isNumberOr()メソッドは、 ratingの値を返すか、 ratingが数値でないか null の場合は1の値を返します。 project()メソッドは、この値を新しいnumericalRatingフィールドとして返します。

次のコードは、この集計のパイプラインを示しています。

var rating = current().getField("rating");
asList(project(fields(
computed("numericalRating", rating
.isNumberOr(of(1)))
)));

次のコードは、Query API で同等の集計パイプラインを提供します。

[ { $project: {
numericalRating: {
$cond: { if: { $isNumber: "$rating" },
then: "$rating",
else: 1
} }
} } ]

戻る

集計