Docs Menu
Docs Home
/ /
Atlas Device SDK
/ /

MongoDB のクエリ - Java SDK

項目一覧

  • ユースケース
  • 前提条件
  • プロジェクトを設定する
  • プロジェクトを設定する
  • MongoDB Atlas Service クラスターのリンク
  • Realm 依存関係のインポート
  • MongoDB コレクション ハンドルのインスタンス化
  • サンプルデータ
  • ドキュメントの作成
  • 単一ドキュメントのインサート
  • 複数のドキュメントの挿入
  • ドキュメントを読む
  • 単一ドキュメントの検索
  • 複数ドキュメントの検索
  • コレクション内のドキュメントをカウント
  • Update Documents
  • 単一ドキュメントの更新
  • 複数のドキュメントの更新
  • ドキュメントをアップサートする
  • Delete Documents
  • 単一ドキュメントの削除
  • 複数のドキュメントの削除
  • 変更の監視
  • コレクションの変更の監視
  • フィルターでコレクションの変更を監視
  • コレクション内のドキュメントの集計
  • フィルター ドキュメント
  • グループ ドキュメント
  • プロジェクト ドキュメント フィールド
  • ドキュメントへのフィールドの追加
  • Unwind Array Values

Realm Java SDK のMongoClientクエリ APIを使用すると、MongoDB Atlas に保存されているデータを Android アプリケーションから直接クエリできます。 Atlas App Servicesは、ログインしたユーザーまたは各ドキュメントの内容に基づいて結果を安全に取得するためのコレクションにデータ アクセスルールを提供します。

次のアクションにより、Realm SDK を使用して Android アプリケーションからリンクされた MongoDB Atlas クラスターにアクセスできるようになります。

注意

このページで説明されている各操作では、クエリを使用して、操作が実行されるコレクション内の特定のドキュメントを照合します。 フィルターがコレクション内の複数のドキュメントに一致する場合、ソートパラメーターを指定しない限り、ドキュメントは不特定の順序で返されます。 つまり、 findOne()updateOne() 、またはdeleteOne()関数のいずれかに並べ替えを指定しないと、操作はクエリに一致する任意のドキュメントと一致する可能性があります。 ソートについて詳しくは、 cursor.sort() を参照してください。

MongoDB データソースをクエリする理由はさまざまあります。 Atlas Device Sync を介してクライアント内のデータを操作することは、必ずしも現実的ではないか、可能な限りありません。 次の場合には、MongoDB をクエリすることをお勧めします。

  • データセットが大きいか、クライアント デバイスにデータセット全体のロードに対する制約がある

  • カスタム ユーザー データを作成または更新している場合

  • Realm でモデル化されていないドキュメントを取得している

  • アプリは厳密なスキーマを持たないコレクションにアクセスする必要があります

  • 非 Realm サービスは、アクセスしたいコレクションを生成します。

網羅的なものではありませんが、これらは MongoDB を直接クエリする一般的なユースケースです。

Android アプリケーションから MongoDB をクエリする前に、App Services App で MongoDB Data Access を設定する必要があります。 バックエンド アプリを設定して Realm SDK クエリ Atlas を使用できるようにする方法については、App Services ドキュメントの「 MongoDB データアクセスの設定 」を参照してください。

1

Realm Java SDK のインストールガイドの手順に従います。

2

MongoDB データソースのリンク 」ガイドの手順に従います。 サービスに意味のある名前を割り当てます。この名前は、Realm SDK を使用してクラスターに接続するために必要になります。

3

リモート MongoDB コレクションに対する CRUD 操作には、次の 1 つ以上のimportステートメントを使用します。

// Base Realm Packages
import io.realm.mongodb.App;
import io.realm.mongodb.AppConfiguration;
// Realm Authentication Packages
import io.realm.mongodb.User;
import io.realm.mongodb.Credentials;
// MongoDB Service Packages
import io.realm.mongodb.mongo.MongoClient;
import io.realm.mongodb.mongo.MongoDatabase;
import io.realm.mongodb.mongo.MongoCollection;
// Utility Packages
import org.bson.Document;
// Base Realm Packages
import io.realm.mongodb.App
import io.realm.mongodb.AppConfiguration
// Realm Authentication Packages
import io.realm.mongodb.User
import io.realm.mongodb.Credentials
// MongoDB Service Packages
import io.realm.mongodb.mongo.MongoClient
import io.realm.mongodb.mongo.MongoDatabase
import io.realm.mongodb.mongo.MongoCollection
// Utility Packages
import org.bson.Document
4

MongoDB のインスタンスに接続するには、MongoDB コレクションへのアクセス権を持つユーザーが必要です。 このようなユーザーとしてアプリケーションにログインし、次のコードを使用してローカル MongoDB コレクション ハンドルをインスタンス化します。

User user = app.currentUser();
MongoClient mongoClient =
user.getMongoClient("mongodb-atlas");
MongoDatabase mongoDatabase =
mongoClient.getDatabase("plant-data-database");
// registry to handle POJOs (Plain Old Java Objects)
CodecRegistry pojoCodecRegistry = fromRegistries(AppConfiguration.DEFAULT_BSON_CODEC_REGISTRY,
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
MongoCollection<Plant> mongoCollection =
mongoDatabase.getCollection(
"plant-data-collection",
Plant.class).withCodecRegistry(pojoCodecRegistry);
Log.v("EXAMPLE", "Successfully instantiated the MongoDB collection handle");
val user = app.currentUser()
val mongoClient =
user!!.getMongoClient("mongodb-atlas")
val mongoDatabase =
mongoClient.getDatabase("plant-data-database")
// registry to handle POJOs (Plain Old Java Objects)
val pojoCodecRegistry = CodecRegistries.fromRegistries(
AppConfiguration.DEFAULT_BSON_CODEC_REGISTRY,
CodecRegistries.fromProviders(
PojoCodecProvider.builder().automatic(true).build()))
val mongoCollection =
mongoDatabase.getCollection(
"plant-data-collection",
Plant::class.java).withCodecRegistry(pojoCodecRegistry)
Log.v("EXAMPLE", "Successfully instantiated the MongoDB collection handle")

注意

MongoDB でのカスタム クラスの使用

MongoDB で組み込みのDocumentクラス以外のクラスを使用するには、 MongoCollectionインスタンスにコーデックを追加できます。 上記の例では、Plain Old Java Object(POJO)をサポートするためにPojoCodecProviderを追加しています。 カスタム オブジェクトをサポートするには 2 つのコーデック プロバイダーが必要です。

  • デフォルトのコーデック プロバイダーは、組み込み Java 型( AppConfiguration.DEFAULT_BSON_CODEC_REGISTRYからアクセス)をサポートします。

  • PojoCodecProviderは、POJO クラスをサポートするための新しいコーデックを自動的に作成します。

SDK は、要求されたクラスのコーデックを返すまで、レジストリを順番に確認します。 そのため、デフォルトのコーデック レジストリを最初に一覧表示する必要があります。また、 PojoCodecProviderはほぼすべてのクラスのコーデックを提供できるため、常に最後の CodecProvider である必要があります。

次の例では、植物店舗のチェーンの在庫を記述する MongoDB コレクションで動作しています。 店舗で販売されるさまざまなプランを説明するドキュメントの次のコレクションについて考えてみましょう。

Plan.java
import org.bson.codecs.pojo.annotations.BsonProperty;
import org.bson.types.ObjectId;
public class Plant {
private ObjectId id;
private String name;
private String sunlight;
private String color;
private String type;
@BsonProperty("_partition")
private String partition;
// empty constructor required for MongoDB Data Access POJO codec compatibility
public Plant() {}
public Plant(ObjectId id, String name, String sunlight, String color, String type, String partition) {
this.id = id;
this.name = name;
this.sunlight = sunlight;
this.color = color;
this.type = type;
this.partition = partition;
}
public ObjectId getId() { return id; }
public void setId(ObjectId id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public String getSunlight() { return sunlight; }
public void setSunlight(String sunlight) { this.sunlight = sunlight; }
public String getColor() { return color; }
public void setColor(String color) { this.color = color; }
public String getType() { return type; }
public void setType(String type) { this.type = type; }
public String getPartition() { return partition; }
public void setPartition(String partition) { this.partition = partition; }
@Override
public String toString() {
return "Plant [id=" + id + ", name=" + name + ", sunlight=" + sunlight + ", color=" + color + ", type=" + type + ", partition=" + partition + "]";
}
}
User user = app.currentUser();
MongoClient mongoClient =
user.getMongoClient("mongodb-atlas");
MongoDatabase mongoDatabase =
mongoClient.getDatabase("plant-data-database");
// registry to handle POJOs (Plain Old Java Objects)
CodecRegistry pojoCodecRegistry = fromRegistries(AppConfiguration.DEFAULT_BSON_CODEC_REGISTRY,
fromProviders(PojoCodecProvider.builder().automatic(true).build()));
MongoCollection<Plant> mongoCollection =
mongoDatabase.getCollection(
"plant-data-collection",
Plant.class).withCodecRegistry(pojoCodecRegistry);
mongoCollection.insertMany(Arrays.asList(
new Plant(new ObjectId(),
"venus flytrap",
"full",
"white",
"perennial",
"Store 42"),
new Plant(new ObjectId(),
"sweet basil",
"partial",
"green",
"annual",
"Store 42"),
new Plant(new ObjectId(),
"thai basil",
"partial",
"green",
"perennial",
"Store 42"),
new Plant(new ObjectId(),
"helianthus",
"full",
"yellow",
"annual",
"Store 42"),
new Plant(new ObjectId(),
"petunia",
"full",
"purple",
"annual",
"Store 47")));
Log.v("EXAMPLE", "Successfully inserted the sample data.");
Plan.kt
import org.bson.codecs.pojo.annotations.BsonProperty
import org.bson.types.ObjectId
open class Plant(val id : ObjectId = ObjectId(),
var name : String? = null,
var sunlight : String? = null,
var color : String? = null,
var type : String? = null,
@field:BsonProperty("_partition") // specify that this is a field-level annotation
var partition : String? = null) {
override fun toString(): String {
return "Plant [id=$id, name=$name, sunlight=$sunlight, color=$color, type=$type, partition=$partition]"
}
}
val user = app.currentUser()
val mongoClient =
user!!.getMongoClient("mongodb-atlas")
val mongoDatabase =
mongoClient.getDatabase("plant-data-database")
// registry to handle POJOs (Plain Old Java Objects)
val pojoCodecRegistry = CodecRegistries.fromRegistries(
AppConfiguration.DEFAULT_BSON_CODEC_REGISTRY,
CodecRegistries.fromProviders(
PojoCodecProvider.builder().automatic(true).build()))
val mongoCollection =
mongoDatabase.getCollection(
"plant-data-collection",
Plant::class.java).withCodecRegistry(pojoCodecRegistry)
mongoCollection.insertMany(
listOf(
Plant(
ObjectId(),
"venus flytrap",
"full",
"white",
"perennial",
"Store 42"
),
Plant(
ObjectId(),
"sweet basil",
"partial",
"green",
"annual",
"Store 42"
),
Plant(
ObjectId(),
"thai basil",
"partial",
"green",
"perennial",
"Store 42"
),
Plant(
ObjectId(),
"helianthus",
"full",
"yellow",
"annual",
"Store 42"
),
Plant(
ObjectId(),
"petunia",
"full",
"purple",
"annual",
"Store 47"
)
)
)
Log.v("EXAMPLE", "Successfully Successfully inserted the sample data.")

これらのコード スニペットは、モバイル アプリケーションから MongoDB コレクションに 1 つ以上のドキュメントを挿入する方法を示しています。 挿入操作は、MongoDB に追加するドキュメントを引数として受け取り、操作の実行結果を含むオブジェクトに解決されるRealmResultTaskを返します。

collection.insertOne() を使用して単一のドキュメントを挿入できます。

次のスニペットは、「 Ops Manager 」の植物を説明する単一のドキュメントを、店舗のグループで販売するプランを説明するドキュメントのコレクションに挿入します。

Plant plant = new Plant(
new ObjectId(),
"lily of the valley",
"full",
"white",
"perennial",
"Store 47");
mongoCollection.insertOne(plant).getAsync(task -> {
if (task.isSuccess()) {
Log.v("EXAMPLE", "successfully inserted a document with id: " + task.get().getInsertedId());
} else {
Log.e("EXAMPLE", "failed to insert documents with: " + task.getError().getErrorMessage());
}
});
val plant = Plant(
ObjectId(),
"lily of the valley",
"full",
"white",
"perennial",
"Store 47"
)
mongoCollection?.insertOne(plant)?.getAsync { task ->
if (task.isSuccess) {
Log.v(
"EXAMPLE",
"successfully inserted a document with id: ${task.get().insertedId}"
)
} else {
Log.e("EXAMPLE", "failed to insert documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully inserted a document with id: BsonObjectId{value=5f19...}

collection.insertMany() を使用して、複数のドキュメントを同時に挿入できます。

次のスニペットは、プランを説明する 3 つのドキュメントを、店舗のグループで販売するプランを説明するドキュメントのコレクションに挿入します。

List<Plant> plants = Arrays.asList(
new Plant(new ObjectId(),
"rhubarb",
"full",
"red",
"perennial",
"Store 47"),
new Plant(new ObjectId(),
"wisteria lilac",
"partial",
"purple",
"perennial",
"Store 42"),
new Plant(new ObjectId(),
"daffodil",
"full",
"yellow",
"perennial",
"Store 42"));
mongoCollection.insertMany(plants).getAsync(task -> {
if (task.isSuccess()) {
int insertedCount = task.get().getInsertedIds().size();
Log.v("EXAMPLE", "successfully inserted " + insertedCount + " documents into the collection.");
} else {
Log.e("EXAMPLE", "failed to insert documents with: ", task.getError());
}
});
val plants = listOf(
Plant(
ObjectId(),
"rhubarb",
"full",
"red",
"perennial",
"Store 47"
),
Plant(
ObjectId(),
"wisteria lilac",
"partial",
"purple",
"perennial",
"Store 42"
),
Plant(
ObjectId(),
"daffodil",
"full",
"yellow",
"perennial",
"Store 42"
)
)
mongoCollection.insertMany(plants).getAsync { task ->
if (task.isSuccess) {
val insertedCount = task.get().insertedIds.size
Log.v(
"EXAMPLE",
"successfully inserted $insertedCount documents into the collection."
)
} else {
Log.e("EXAMPLE", "failed to insert documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully inserted 3 documents into the collection.

これらのコード スニペットは、 モバイルアプリケーションからMongoDBコレクションに保存されているデータを読み取る方法を示しています。読み取り操作では、 クエリ を使用して、データベースから返されるドキュメントを指定します。読み取り操作は Task を返します は、単一の一致したドキュメント(findOne() longcount()の場合)、 数値( の場合)、または一致したドキュメントのコレクションを走査できるイテレータ(find() の場合)のいずれかに解決されます。 の)。

collection.findOne() を使用して単一のドキュメントを検索できます。

次のスニペットは、植物ドキュメントのtypeフィールドに string 値「perennial」が含まれるグループで販売されている植物を説明するドキュメントのコレクションから 1 つのドキュメントを検索します。

Document queryFilter = new Document("type", "perennial");
mongoCollection.findOne(queryFilter).getAsync(task -> {
if (task.isSuccess()) {
Plant result = task.get();
Log.v("EXAMPLE", "successfully found a document: " + result);
} else {
Log.e("EXAMPLE", "failed to find document with: ", task.getError());
}
});
val queryFilter = Document("type", "perennial")
mongoCollection.findOne(queryFilter)
.getAsync { task ->
if (task.isSuccess) {
val result = task.get()
Log.v("EXAMPLE", "successfully found a document: $result")
} else {
Log.e("EXAMPLE", "failed to find document with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully found a document: Plant [id=5f18..., name=venus flytrap, sunlight=full, color=white, type=perennial, partition=Store 42]

collection.find() を使用して複数のドキュメントを見つけることができます。

次のスニペットは、値が「 Store 42 _partitionである という名前のフィールドを含む店舗のグループに販売されているプランを説明するドキュメントのコレクション内のすべてのドキュメントを検索します。

Document queryFilter = new Document("_partition", "Store 42");
RealmResultTask<MongoCursor<Plant>> findTask = mongoCollection.find(queryFilter).iterator();
findTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Plant> results = task.get();
Log.v("EXAMPLE", "successfully found all plants for Store 42:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to find documents with: ", task.getError());
}
});
val queryFilter = Document("_partition", "Store 42")
val findTask = mongoCollection.find(queryFilter).iterator()
findTask.getAsync { task ->
if (task.isSuccess) {
val results = task.get()
Log.v("EXAMPLE", "successfully found all plants for Store 42:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE", "failed to find documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully found all plants for Store 42:
V/EXAMPLE: Plant [id=5f18..., name=venus flytrap, sunlight=full, color=white, type=perennial, partition=Store 42]
V/EXAMPLE: Plant [id=5f18..., name=sweet basil, sunlight=partial, color=green, type=annual, partition=Store 42]
V/EXAMPLE: Plant [id=5f18..., name=thai basil, sunlight=partial, color=green, type=perennial, partition=Store 42]
V/EXAMPLE: Plant [id=5f18..., name=helianthus, sunlight=full, color=yellow, type=annual, partition=Store 42]

collection.count()を使用してコレクション内のドキュメントをカウントできます。 どのドキュメントをカウントするかを決定するために、任意のクエリを指定できます。 クエリを指定しない場合、アクションはコレクション内のすべてのドキュメントをカウントします。

次のスニペットは、店舗のグループで販売されるプランを説明するドキュメントのコレクション内のドキュメントの数をカウントします。

mongoCollection.count().getAsync(task -> {
if (task.isSuccess()) {
long count = task.get();
Log.v("EXAMPLE",
"successfully counted, number of documents in the collection: " +
count);
} else {
Log.e("EXAMPLE", "failed to count documents with: ", task.getError());
}
});
mongoCollection.count().getAsync { task ->
if (task.isSuccess) {
val count = task.get()
Log.v("EXAMPLE", "successfully counted, number of documents in the collection: $count")
} else {
Log.e("EXAMPLE", "failed to count documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully counted, number of documents in the collection: 5

これらのコード スニペットは、モバイル アプリケーションから MongoDB コレクションに保存されているデータをアップデートする方法を示しています。 更新操作では、クエリを使用して更新するドキュメントを指定し、更新演算子を使用してクエリに一致するドキュメントをミューテーションする方法を記述します。 更新操作は タスク を返します は、操作の実行結果を含むオブジェクトに解決されます。

collection.updateOne() を使用して単一のドキュメントを更新できます。

次のスニペットは、 店舗 のグループで販売されるプランを説明するドキュメントのコレクション内の 1 つのドキュメントを更新します。 この操作は、 nameフィールドに値「ペナルティ」が含まれているドキュメントをクエリし、最初に一致したドキュメントのsunlightフィールドの値を「部分的」に変更します。

Document queryFilter = new Document("name", "petunia");
Document updateDocument = new Document("$set", new Document("sunlight", "partial"));
mongoCollection.updateOne(queryFilter, updateDocument).getAsync(task -> {
if (task.isSuccess()) {
long count = task.get().getModifiedCount();
if (count == 1) {
Log.v("EXAMPLE", "successfully updated a document.");
} else {
Log.v("EXAMPLE", "did not update a document.");
}
} else {
Log.e("EXAMPLE", "failed to update document with: ", task.getError());
}
});
val queryFilter = Document("name", "petunia")
val updateDocument = Document("\$set", Document("sunlight", "partial"))
mongoCollection.updateOne(queryFilter, updateDocument).getAsync { task ->
if (task.isSuccess) {
val count = task.get().modifiedCount
if (count == 1L) {
Log.v("EXAMPLE", "successfully updated a document.")
} else {
Log.v("EXAMPLE", "did not update a document.")
}
} else {
Log.e("EXAMPLE", "failed to update document with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully updated a document.

コレクション.updateMany() を使用して複数のドキュメントを更新できます。

次のスニペットは、 店舗 のグループで販売されるプランを説明するドキュメントのコレクション内の複数のドキュメントを更新します。 この操作は、 _partitionフィールドに値「 47が含まれているドキュメントをクエリし、一致する各ドキュメントの_partitionフィールドの値を「 51を保存」に変更します。

Document queryFilter = new Document("_partition", "Store 47");
Document updateDocument = new Document("$set", new Document("_partition", "Store 51"));
mongoCollection.updateMany(queryFilter, updateDocument).getAsync(task -> {
if (task.isSuccess()) {
long count = task.get().getModifiedCount();
if (count != 0) {
Log.v("EXAMPLE", "successfully updated " + count + " documents.");
} else {
Log.v("EXAMPLE", "did not update any documents.");
}
} else {
Log.e("EXAMPLE", "failed to update documents with: ", task.getError());
}
});
val queryFilter = Document("_partition", "Store 47")
val updateDocument = Document("\$set", Document("_partition", "Store 51"))
mongoCollection.updateMany(queryFilter, updateDocument).getAsync { task ->
if (task.isSuccess) {
val count = task.get().modifiedCount
if (count != 0L) {
Log.v("EXAMPLE", "successfully updated $count documents.")
} else {
Log.v("EXAMPLE", "did not update any documents.")
}
} else {
Log.e("EXAMPLE", "failed to update documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully updated 2 documents.

アップデート操作がコレクション内のどのドキュメントにも一致しない場合は、 upsertオプションをtrueに設定することで、アップデート クエリに一致する新しいドキュメントを 1 つ自動的に挿入できます。

次のスニペットは、店舗のグループで販売されているプランを説明するドキュメントのコレクション内のドキュメントを更新するか、クエリに一致するドキュメントがない場合は新しいドキュメントを挿入します。 この操作は、次のドキュメントをクエリします。

  • sunlightフィールドの値は「Full」

  • typeフィールドの値は「perennial」

  • colorフィールドの値は「green」

  • _partitionフィールドの値が「Store 47」である

このスニペットはupsertオプションをtrueに設定しているため、クエリに一致するドキュメントがない場合、MongoDB はクエリと指定された更新の両方を含む新しいドキュメントを作成します。

Document queryFilter = new Document("sunlight", "full")
.append("type", "perennial")
.append("color", "green")
.append("_partition", "Store 47");
Document updateDocument = new Document("$set", new Document("name", "sweet basil"));
UpdateOptions updateOptions = new UpdateOptions().upsert(true);
mongoCollection.updateOne(queryFilter, updateDocument, updateOptions).getAsync(task -> {
if (task.isSuccess()) {
if(task.get().getUpsertedId() != null) {
Log.v("EXAMPLE", "successfully upserted a document with id " +
task.get().getUpsertedId());
} else {
Log.v("EXAMPLE", "successfully updated a document.");
}
} else {
Log.e("EXAMPLE", "failed to update or insert document with: ",
task.getError());
}
});
val queryFilter = Document("sunlight", "full")
.append("type", "perennial")
.append("color", "green")
.append("_partition", "Store 47")
val updateDocument = Document("\$set", Document("name", "sweet basil"))
val updateOptions = UpdateOptions().upsert(true)
mongoCollection.updateOne(queryFilter, updateDocument, updateOptions)
.getAsync { task ->
if (task.isSuccess) {
if (task.get().upsertedId != null) {
Log.v("EXAMPLE", "successfully upserted a document with id ${task.get().upsertedId}")
} else {
Log.v("EXAMPLE", "successfully updated a document.")
}
} else {
Log.e("EXAMPLE", "failed to update or insert document with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully upserted a document with id: BsonObjectId{value=5f19...}

これらのコード スニペットは、MongoDB コレクションに保存されているドキュメントをモバイル アプリケーションから削除する方法を示しています。 削除操作はクエリを使用して、削除するドキュメントを指定し、 タスク を返す は、操作の実行結果を含むオブジェクトに解決されます。

collection.deleteOne() を使用して、コレクションから 1 つのドキュメントを削除できます。

次のスニペットは、 店舗のグループで販売されるプランを説明するドキュメントのコレクション内の 1 つのドキュメントを削除します。 この操作は、 colorフィールドの値が「green」であるドキュメントをクエリし、クエリに一致する最初のドキュメントを削除します。

Document queryFilter = new Document("color", "green");
mongoCollection.deleteOne(queryFilter).getAsync(task -> {
if (task.isSuccess()) {
long count = task.get().getDeletedCount();
if (count == 1) {
Log.v("EXAMPLE", "successfully deleted a document.");
} else {
Log.v("EXAMPLE", "did not delete a document.");
}
} else {
Log.e("EXAMPLE", "failed to delete document with: ", task.getError());
}
});
val queryFilter = Document("color", "green")
mongoCollection.deleteOne(queryFilter).getAsync { task ->
if (task.isSuccess) {
val count = task.get().deletedCount
if (count == 1L) {
Log.v("EXAMPLE", "successfully deleted a document.")
} else {
Log.v("EXAMPLE", "did not delete a document.")
}
} else {
Log.e("EXAMPLE", "failed to delete document with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully deleted a document.

collection.deleteMany() を使用して、コレクションから複数の項目を削除できます。

次のスニペットは、 sunlightフィールド値が「 full 」と「 」のtypeフィールド値の両方を含むクエリに一致する店舗のグループに販売されているプランを説明するドキュメントのコレクション内のすべてのドキュメントを削除します。 ".

Document queryFilter = new Document("sunlight", "full")
.append("type", "annual");
mongoCollection.deleteMany(queryFilter).getAsync(task -> {
if (task.isSuccess()) {
long count = task.get().getDeletedCount();
if (count != 0) {
Log.v("EXAMPLE", "successfully deleted " + count + " documents.");
} else {
Log.v("EXAMPLE", "did not delete any documents.");
}
} else {
Log.e("EXAMPLE", "failed to delete documents with: ", task.getError());
}
});
val queryFilter = Document("sunlight", "full").append("type", "annual")
mongoCollection.deleteMany(queryFilter).getAsync { task ->
if (task.isSuccess) {
val count = task.get().deletedCount
if (count != 0L) {
Log.v("EXAMPLE", "successfully deleted $count documents.")
} else {
Log.v("EXAMPLE", "did not delete any documents.")
}
} else {
Log.e("EXAMPLE", "failed to delete documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: succcessfully deleted 2 documents.

これらのコード スニペットは、コレクションに対する監視操作を構成して実行する方法を示しています。

重要

サーバーレスの制限事項

データソースが Atlas サーバーレスインスタンスの場合、変更を監視することはできません。 MongoDB サーバーレスは現在、変更をリッスンするために監視対象コレクションで使用される 変更ストリーム をサポートしていません。

collection.watch()またはcollection.watchAsync( ) を呼び出すと、コレクションに加えられた変更のストリームを開くことができます。 監視対象オブジェクトのオブジェクト ID を 変数の引数として渡すことで、コレクション内の特定のドキュメントに対する変更を監視できます。

次のスニペットは、 plantsコレクション内のドキュメントに対する変更を監視します。

RealmEventStreamAsyncTask<Plant> watcher = mongoCollection.watchAsync();
watcher.get(result -> {
if (result.isSuccess()) {
Log.v("EXAMPLE", "Event type: " +
result.get().getOperationType() + " full document: " +
result.get().getFullDocument());
} else {
Log.e("EXAMPLE", "failed to subscribe to changes in the collection with : ",
result.getError());
}
});
Plant triffid = new Plant(
new ObjectId(),
"triffid",
"low",
"green",
"perennial",
"Store 47");
mongoCollection.insertOne(triffid).getAsync(task -> {
if (task.isSuccess()) {
BsonObjectId insertedId = task.get().getInsertedId().asObjectId();
Log.v("EXAMPLE", "successfully inserted a document with id " + insertedId);
} else {
Log.e("EXAMPLE", "failed to insert document with: ", task.getError());
}
});
val watcher = mongoCollection.watchAsync()
watcher[{ result ->
if (result.isSuccess) {
Log.v("EXAMPLE", "Event type: ${result.get().operationType} full document: ${result.get().fullDocument}")
} else {
Log.e("EXAMPLE", "failed to subscribe to changes in the collection with : ${result.error}")
}
}]
val triffid =
Plant(
ObjectId(),
"triffid",
"low",
"green",
"perennial",
"Store 47"
)
mongoCollection.insertOne(triffid).getAsync { task ->
if (task.isSuccess) {
val insertedId = task.get().insertedId.asObjectId()
Log.v("EXAMPLE", "successfully inserted a document with id $insertedId")
} else {
Log.e("EXAMPLE", "failed to insert document with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully inserted a document with id BsonObjectId{value=5f6bb...}
V/EXAMPLE: Event type: INSERT full document: Plant [id=5f6bb..., name=triffid, sunlight=low, color=green, type=perennial, partition=Store 47]

collection.watchWithFilter()またはcollection.watchWithFilterAsync( ) を呼び出すと、特定の条件を満たすコレクション内のドキュメントに加えられた変更のストリームを開くことができます。 どちらのメソッドも、コレクションの監視中に発生する各 データベース イベント を処理するために $match 演算子 のクエリとして使用される またはDocument BsonDocumentパラメーターを受け入れます。

次のスニペットは、 plantsコレクション内のドキュメントに対する変更を監視しますが、「 Store 42 」という名前のパーティションに属するドキュメントに対応するイベントについては、提供されているコールバックのみをトリガーします。

RealmEventStreamAsyncTask<Plant> watcher = mongoCollection
.watchWithFilterAsync(new Document("fullDocument._partition", "Store 42"));
watcher.get(result -> {
if (result.isSuccess()) {
Log.v("EXAMPLE", "Event type: " +
result.get().getOperationType() + " full document: " +
result.get().getFullDocument());
} else {
Log.e("EXAMPLE",
"failed to subscribe to filtered changes in the collection with : ",
result.getError());
}
});
List<Plant> plants = Arrays.asList(
new Plant(
new ObjectId(),
"triffid",
"low",
"green",
"perennial",
"Store 47"),
new Plant(
new ObjectId(),
"venomous tentacula",
"low",
"brown",
"annual",
"Store 42"
));
mongoCollection.insertMany(plants).getAsync(task -> {
if (task.isSuccess()) {
int insertedCount = task.get().getInsertedIds().size();
Log.v("EXAMPLE", "successfully inserted " +
insertedCount + " documents into the collection.");
} else {
Log.e("EXAMPLE", "failed to insert documents with: ",
task.getError());
}
});
val watcher = mongoCollection
.watchWithFilterAsync(Document("fullDocument._partition", "Store 42"))
watcher[{ result ->
if (result.isSuccess) {
Log.v("EXAMPLE", "Event type: ${result.get().operationType} full document: ${result.get().fullDocument}")
} else {
Log.e("EXAMPLE", "failed to subscribe to filtered changes in the collection with : ${result.error}")
}
}]
val plants = listOf(
Plant(
ObjectId(),
"triffid",
"low",
"green",
"perennial",
"Store 47"
),
Plant(
ObjectId(),
"venomous tentacula",
"low",
"brown",
"annual",
"Store 42"
)
)
mongoCollection.insertMany(plants).getAsync { task ->
if (task.isSuccess) {
val insertedCount = task.get().insertedIds.size
Log.v("EXAMPLE", "successfully inserted $insertedCount documents into the collection.")
} else {
Log.e("EXAMPLE", "failed to insert documents with: ${task.error}")
}
}

このスニペットを実行すると、次のような出力が生成されます。

V/EXAMPLE: successfully inserted 2 documents into the collection
V/EXAMPLE: Event type: INSERT full document: Plant [id=5f6bb..., name=venomous tentacula, sunlight=low, color=brown, type=annual, partition=Store 42]

集計操作は、集計パイプラインと呼ばれる一連のデータ集計ステージを通じてコレクション内のすべてのドキュメントを実行します。 集計を使用すると、ドキュメントのフィルタリングと変換、関連するドキュメントのグループに関するサマリー データの収集、その他の複雑なデータ操作が可能になります。

collection.aggregate() を使用して集計パイプラインを実行できます。

集計操作は、集計ステージのリストを入力として受け入れ、 タスク を返します パイプラインによって処理されたドキュメントのコレクションに解決されます。

$matchステージを使用して、Query APIクエリフィルターに従ってドキュメントをフィルタリングできます。

{
"$match": {
"<Field Name>": <Query Expression>,
...
}
}

次の$matchステージでは、ドキュメントをフィルタリングして、 typeフィールドの値が「perennial」と等しいドキュメントのみを含めます。

// create an aggregation pipeline
List<Document> pipeline = Arrays.asList(
new Document("$match",
new Document("type",
new Document("$eq", "perennial"))));
// query mongodb using the pipeline
RealmResultTask<MongoCursor<Document>> aggregationTask =
mongoCollection.aggregate(pipeline).iterator();
// handle success or failure of the query
aggregationTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Document> results = task.get();
// iterate over and print the results to the log
Log.v("EXAMPLE", "successfully aggregated the plants. Results:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to aggregate documents with: ",
task.getError());
}
});
// create an aggregation pipeline
val pipeline =
listOf(
Document("\$match",
Document("type",
Document("\$eq", "perennial")
)
)
)
// query mongodb using the pipeline
val aggregationTask = mongoCollection.aggregate(pipeline).iterator()
// handle success or failure of the query
aggregationTask.getAsync { task: App.Result<MongoCursor<Document>> ->
if (task.isSuccess) {
val results = task.get()
// iterate over and print the results to the log
Log.v("EXAMPLE",
"successfully aggregated the plants. Results:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE",
"failed to aggregate documents with: ${task.error}")
}
}

$groupステージを使用して、1 つ以上のドキュメントのサマリーデータを集計できます。 MongoDB は、 $groupステージの_idフィールド値で定義された式に基づいてドキュメントをグループ化します。 フィールド名の前に$を付けることで、特定のドキュメント フィールドを参照できます。

次のスニペットは、 plantsコレクション内のすべてのドキュメントをtype値でグループ化し、各タイプの数を集計します。

// create an aggregation pipeline
List<Document> pipeline = Arrays.asList(
new Document("$group", new Document("_id", "$type")
.append("totalCount", new Document("$sum", 1))));
// query mongodb using the pipeline
RealmResultTask<MongoCursor<Document>> aggregationTask =
mongoCollection.aggregate(pipeline).iterator();
// handle success or failure of the query
aggregationTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Document> results = task.get();
// iterate over and print the results to the log
Log.v("EXAMPLE", "successfully aggregated the plants. Results:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to aggregate documents with: ",
task.getError());
}
});
// create an aggregation pipeline
val pipeline =
listOf(
Document("\$group",
Document("_id", "\$type")
.append("totalCount", Document("\$sum", 1))
)
)
// query mongodb using the pipeline
val aggregationTask = mongoCollection.aggregate(pipeline).iterator()
// handle success or failure of the query
aggregationTask.getAsync { task: App.Result<MongoCursor<Document>> ->
if (task.isSuccess) {
val results = task.get()
// iterate over and print the results to the log
Log.v("EXAMPLE",
"successfully aggregated the plants. Results:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE",
"failed to aggregate documents with: ${task.error}")
}
}

$projectステージを使用して、ドキュメントの特定のフィールドを含めたり省略したりできます。 さらに、集計演算子を使用して新しいフィールドを計算することもできます。 プロジェクションは、次の 2 つの方法で機能します。

  • 値により 1 のフィールドが明示的に含められます。 これには、指定されていないすべてのフィールドを暗黙的に除外するという副作用があります。

  • 値が 0 のフィールドを暗黙的に除外します。これには、指定されていないすべてのフィールドが暗黙的に含まれるという副作用があります。

これらの 2 つのプロジェクション方法は相互に排他的です。つまり、フィールドを明示的に含める場合は、フィールドを明示的に除外することはできません。また、その逆も同様です。

注意

_idフィールドは特別なケースで、明示的に指定されない限り、すべてのクエリに常に含まれます。 このため、 0値を持つ_idフィールド除外しながら、同時に_partitionなどの他のフィールドを1とともに含めることができます。 _idフィールドを除外するという特別なケースのみ、1 つの$projectステージで除外と包含の両方が許可されます。

{
"$project": {
"<Field Name>": <0 | 1 | Expression>,
...
}
}

次の$projectステージでは、 _idフィールドが省略され、 nameフィールドが含まれ、 storeNumberという名前の新しいフィールドが作成されます。 storeNumberは 2 つの集計演算子を使用して生成されます。

  1. $split は、_partition 値をスペース文字で囲む 2 つのstringセグメントに分割します。 たとえば、この方法で分割された値「Store 42」は、「store」と「42」の 2 つの要素を含む配列を返します。

  2. $arrayElemAt は、2 番目の引数に基づいて配列から特定の要素を選択します。 この場合、値1は、 0の配列インデックス以降、 $split演算子によって生成された配列から 2 番目の要素を選択します。 たとえば、この操作に渡される値 ["store", "42"] は "42" の値を返します。

// create an aggregation pipeline
List<Document> pipeline = Arrays.asList(
new Document("$project",
new Document("_id", 0)
.append("name", 1)
.append("storeNumber",
new Document("$arrayElemAt",
Arrays.asList(
new Document("$split",
Arrays.asList("$_partition", " ")),
1)))));
// query mongodb using the pipeline
RealmResultTask<MongoCursor<Document>> aggregationTask =
mongoCollection.aggregate(pipeline).iterator();
// handle success or failure of the query
aggregationTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Document> results = task.get();
// iterate over and print the results to the log
Log.v("EXAMPLE", "successfully aggregated the plants. Results:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to aggregate documents with: ",
task.getError());
}
});
// create an aggregation pipeline
val pipeline =
listOf(
Document("\$project",
Document("_id", 0)
.append("name", 1)
.append("storeNumber",
Document("\$arrayElemAt",
listOf(
Document("\$split",
listOf(
"\$_partition",
" "
)
),
1
)
)
)
)
)
// query mongodb using the pipeline
val aggregationTask = mongoCollection.aggregate(pipeline).iterator()
// handle success or failure of the query
aggregationTask.getAsync { task: App.Result<MongoCursor<Document>> ->
if (task.isSuccess) {
val results = task.get()
// iterate over and print the results to the log
Log.v("EXAMPLE",
"successfully aggregated the plants. Results:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE",
"failed to aggregate documents with: ${task.error}")
}
}

$addFieldsステージを使用して、集計演算子を使用して計算された値を持つ新しいフィールドを追加できます。

注意

$addFields$projectに似ていますが、フィールドを含めたり省略したりすることはできません。

次の$addFieldsステージでは、 storeNumberという名前の新しいフィールドが作成されます。値は_partitionフィールドの値を変換する 2 つの集計演算子の出力です。

// create an aggregation pipeline
List<Document> pipeline = Arrays.asList(
new Document("$addFields",
new Document("storeNumber",
new Document("$arrayElemAt", Arrays.asList(
new Document("$split", Arrays.asList(
"$_partition", " ")), 1)))));
// query mongodb using the pipeline
RealmResultTask<MongoCursor<Document>> aggregationTask =
mongoCollection.aggregate(pipeline).iterator();
// handle success or failure of the query
aggregationTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Document> results = task.get();
// iterate over and print the results to the log
Log.v("EXAMPLE", "successfully aggregated the plants. Results:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to aggregate documents with: ",
task.getError());
}
});
// create an aggregation pipeline
val pipeline =
listOf(
Document("\$addFields",
Document("storeNumber",
Document("\$arrayElemAt",
listOf(
Document("\$split",
listOf(
"\$_partition",
" "
)
),
1
)
)
)
)
)
// query mongodb using the pipeline
val aggregationTask = mongoCollection.aggregate(pipeline).iterator()
// handle success or failure of the query
aggregationTask.getAsync { task: App.Result<MongoCursor<Document>> ->
if (task.isSuccess) {
val results = task.get()
// iterate over and print the results to the log
Log.v("EXAMPLE",
"successfully aggregated the plants. Results:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE",
"failed to aggregate documents with: ${task.error}")
}
}

$unwindステージを使用して、配列を含む単一のドキュメントを、その配列の個々の値を含む複数のドキュメントに変換できます。 配列フィールドを展開すると、MongoDB は配列フィールドの要素ごとに各ドキュメントを 1 回コピーしますが、コピーごとに配列値を配列要素に置き換えます。

{
$unwind: {
path: <Array Field Path>,
includeArrayIndex: <string>,
preserveNullAndEmptyArrays: <boolean>
}
}

次の$unwindステージでは、各ドキュメントのitems配列の要素ごとに新しいドキュメントが作成されます。 また、元の配列内の要素の位置インデックスを指定するitemIndexというフィールドも新しいドキュメントに追加されます。

// create an aggregation pipeline
List<Document> pipeline = Arrays.asList(
new Document("$unwind", new Document("path", "$items")
.append("includeArrayIndex", "itemIndex")));
// query mongodb using the pipeline
RealmResultTask<MongoCursor<Document>> aggregationTask = mongoCollection.aggregate(pipeline).iterator();
// handle success or failure of the query
aggregationTask.getAsync(task -> {
if (task.isSuccess()) {
MongoCursor<Document> results = task.get();
// iterate over and print the results to the log
Log.v("EXAMPLE", "successfully aggregated the plants. Results:");
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString());
}
} else {
Log.e("EXAMPLE", "failed to aggregate documents with: ",
task.getError());
}
});
// create an aggregation pipeline
val pipeline =
listOf(
Document("\$unwind", Document("path", "\$items")
.append("includeArrayIndex", "itemIndex"))
)
// query mongodb using the pipeline
val aggregationTask = mongoCollection.aggregate(pipeline).iterator()
// handle success or failure of the query
aggregationTask.getAsync { task: App.Result<MongoCursor<Document>> ->
if (task.isSuccess) {
val results = task.get()
// iterate over and print the results to the log
Log.v("EXAMPLE",
"successfully aggregated the plants. Results:")
while (results.hasNext()) {
Log.v("EXAMPLE", results.next().toString())
}
} else {
Log.e("EXAMPLE",
"failed to aggregate documents with: ${task.error}")
}
}

の購入に関するコレクションの次のドキュメントを検討します。

{
_id: 123,
customerId: 24601,
items: [
{ name: "Baseball", quantity: 5 },
{ name: "Baseball Mitt", quantity: 1 },
{ name: "Baseball Bat", quantity: 1 },
]
}

このドキュメントに例の$unwindステージを適用すると、ステージは次の 3 つのドキュメントを出力します。

{
_id: 123,
customerId: 24601,
itemIndex: 0,
items: { name: "Baseball", quantity: 5 }
}, {
_id: 123,
customerId: 24601,
itemIndex: 1,
items: { name: "Baseball Mitt", quantity: 1 }
}, {
_id: 123,
customerId: 24601,
itemIndex: 2,
items: { name: "Baseball Bat", quantity: 1 }
}

戻る

関数の呼び出し