このページでは、 Kotlin SDK を使用してローカルまたは同期された Realm 内の既存の Realm オブジェクトを更新する方法について説明します。 Realm でオブジェクトを作成する方法の詳細については、「 Realm オブジェクトの作成 - Kotlin SDK 」を参照してください。
Realm は、Realm オブジェクトと埋め込みオブジェクトに対するアップデートとアップサート操作をサポートしています。 アップサート操作では、オブジェクトの新しいインスタンスが挿入されるか、特定の条件を満たす既存のオブジェクトが更新されます。 詳細については、このページの [ Realm オブジェクトのアップサート ]セクションを参照してください。
非対称オブジェクトは更新できません。 これは、非対称オブジェクトが Realm に永続しない特殊な書込み専用オブジェクトであるためです。 For information on how to use asymmetric objects in your application, refer to Stream Data to Atlas - Kotlin SDK.
注意
同期された Realm への書き込み
Realm 内のオブジェクトを更新する構文は、ローカル Realm または同期された Realm で同じです。 ただし、同期された Realm での書込み (write) 操作が成功するかどうかを判断する追加の考慮事項があります。 詳細については、「 同期された Realm へのデータの書き込み - Kotlin SDK 」を参照してください。
アップデート操作
アップデート操作やアップサート操作を含め、Realm を変更するすべての操作は、書込みトランザクション内で実行する必要があります。 書込みトランザクションは、Realm のwrite () メソッドまたはwriteBlocking()メソッドに渡されます。 このコールバック内でMutableRealmインスタンスにアクセスし、Realm 内のオブジェクトを更新できます。 書込みトランザクションと Realm がそれを処理する方法の詳細については、「 書込みトランザクション 」を参照してください。
さらに、書込みトランザクション内でのみアクセスできるライブ オブジェクトのみを変更できます。 MutableRealm.findLarge() を使用してトランザクション内で固定されたオブジェクトを実行中のオブジェクトに変換できます。
例
変更する前に凍結されたオブジェクトを変換する
val frozenFrog = realm.query<Frog>().find().first() // Open a write transaction realm.write { // Get the live frog object with findLatest(), then update it findLatest(frozenFrog)?.let { liveFrog -> liveFrog.name = "Kermit" liveFrog.age -= 1 } }
既存のオブジェクトの更新
Realm 内に保存されている Realm オブジェクトまたは埋め込みオブジェクトのプロパティを変更するには、次の手順に従います。
Realm.write()を使用して書込みトランザクションを開きます またはRealm.writeBlocking() の
query()を使用して、変更するオブジェクトをトランザクションの可変邦土をクエリして、ライブ オブジェクトを取得します。
query()に渡される型パラメータとしてオブジェクトタイプを指定します。(任意)クエリを指定して、返されたオブジェクトのセットをフィルタリングします。 クエリフィルターを含めない場合、指定された型のすべてのオブジェクトが返されます。 Kotlin SDK を使用したクエリの詳細については、「 Realm オブジェクトの読み取り - Kotlin SDK 」を参照してください。
重要
オブジェクトはライブでなければなりません
変更できるのは、ライブ オブジェクトのみです。 クエリが書込みトランザクションの外部で発生する場合は、
mutableRealm.findLatest()を使用してトランザクション内で固定オブジェクトをライブ オブジェクトに変換する必要があります。書込みトランザクション (write transaction)内でオブジェクトを変更します。適用ブロック を使用して、一度に複数のプロパティを構成できます。 Realm が書込みトランザクション (write transaction)をコミットすると、すべての変更は自動的に邦土に永続化されます。
注意
String またはバイト配列の更新
Realm はフィールド全体を操作するため、文字列またはバイト配列の個々の要素を直接更新することはできません。 代わりに、フィールド全体を読み取り、個々の要素に変更を加えてから、フィールド全体をトランザクション ブロックで再度書き戻す必要があります。
Realm オブジェクトの更新
Realm オブジェクトを更新するには、更新対象の特定のオブジェクトを返すフィルターを使用して タイプのクエリを実行します。 次に、オブジェクトのプロパティを変更します。
次の例では、プライマリキーでFrogオブジェクトをクエリし、 nameとageプロパティを更新します。
// Query and update a realm object in a single write transaction realm.write { val liveFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first() liveFrog.name = "Michigan J. Frog" liveFrog.age += 1 }
埋め込みオブジェクトの更新
埋め込みオブジェクトは、個々のプロパティを変更するか、埋め込みオブジェクト全体を上書きすることで更新できます。
Tip
ドット表記で埋め込みオブジェクトにアクセス
ドット表記 を使用して、通常のネストされたオブジェクトと同様に埋め込みオブジェクトのプロパティにアクセスできます。 詳細については、 「 埋め込みオブジェクト プロパティでフィルタリング 」を参照してください。
埋め込みオブジェクト内の 1 つ以上のプロパティを更新するには、親オブジェクトまたは埋め込みオブジェクトを取得し、書込みトランザクション (write transaction) で埋め込みオブジェクトのプロパティを再割り当てします。
次の例では、埋め込みEmbeddedAddressオブジェクトを含むContactオブジェクトがあります。 埋め込みオブジェクトのプロパティをいくつかの操作でアップデートします。
// Modify embedded object properties in a write transaction realm.write { // Fetch the objects val addressToUpdate = findLatest(address) ?: error("Cannot find latest version of embedded object") val contactToUpdate = findLatest(contact) ?: error("Cannot find latest version of parent object") // Update a single embedded object property directly addressToUpdate.street = "100 10th St N" // Update multiple properties addressToUpdate.apply { street = "202 Coconut Court" city = "Los Angeles" state = "CA" postalCode = "90210" } // Update property through the parent object contactToUpdate.address?.state = "NY" }
埋め込みオブジェクトを完全に上書きするには、書込みトランザクション(write transaction)で新しい埋め込みオブジェクトのインスタンスを親プロパティに割り当てます。 これにより、既存の埋め込みオブジェクトが削除されます。
次の例では、埋め込みEmbeddedAddressオブジェクトを含むContactオブジェクトがあります。 新しいEmbeddedAddressオブジェクトを定義し、それを親プロパティに割り当てます。
realm.write { val parentObject = query<Contact>("_id == $0", PRIMARY_KEY_VALUE).find().first() val newAddress = EmbeddedAddress().apply { propertyOwner = Contact().apply { name = "Michigan J. Frog" } street = "456 Lily Pad Ln" country = EmbeddedCountry().apply { name = "Canada" } } // Overwrite the embedded object with the new instance (deletes the existing object) parentObject.address = newAddress }
複数のオブジェクトの更新
Realm 内の複数のオブジェクトを更新することもできます。
Realm.write()を使用して書込みトランザクションを開きます またはRealm.writeBlocking() の
クエリによって返されたRealmResultのセットの要素を更新します。
val tadpoles = realm.query<Frog>("age <= $0", 2) for (tadpole in tadpoles.find()) { realm.write { findLatest(tadpole)?.name = tadpole.name + " Jr." } }
Realm プロパティの更新
オブジェクトタイプの定義方法によっては、 Realm 固有の特別なタイプであるプロパティがある場合があります。
MutableRealmInt(counter)プロパティを更新
次の Realm API 関数を使用して、 MutableRealmIntプロパティ値を更新できます。
increment()decrement()set()
これらのメソッドは、ミューテーションされた値を持つMutableRealmIntプロパティを返します。
Tip
set() 演算子の使用に注意が必要
set()演算子は、 increment()またはdecrement()への以前の呼び出しを上書きします。 ユースケースでファジーカウントが受け入れられない限り、 set()をincrement()またはdecrement()と混在させることは推奨されません。
Realm API関数に加えて、Kotlin の標準ライブラリが提供するものと同様の、Long の次の演算子セットとインデックス関数を使用することもできます。
非接頭辞演算子:
unaryPlus、unaryMinusインクリメント演算子とデクリメント演算子:
inc、dec(increment、decrementと混同しないでください)算術演算子:
plus、minus、times、div、rem等価演算子:
equals比較演算子:
compareToBitwise functions:
shl,shr,ushr,and,or,xor,inv
ただし、これらの演算子とインデックス関数は、それが呼び出されるインスタンスをミューテーションしません。 代わりに、操作の結果を持つ新しい非マネージド インスタンスが返されます。
重要
Realm メソッドのみがミューテーションされた値を生成します
ミューテーションされた値を生成する操作は、Realm API 関数であるincrement 、 decrement 、 setのみです。 他のすべての操作( incとdecを含む)は、新しい 値を持つ非マネージド インスタンスを返します。
次の例では、 increment() 、 decrement() 、 set()操作を使用してMutableRealmIntプロパティを更新します。
// Open a write transaction realm.write { // Get the live object val frog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first() val counter: MutableRealmInt? = frog.fliesEaten counter?.get() // 1 // Increment the value of the MutableRealmInt property // ** Note use of decrement() with negative value ** counter?.increment(0) // 1 counter?.increment(5) // 6 counter?.decrement(-2) // 8 // Decrement the value of the MutableRealmInt property // ** Note use of increment() with negative value ** counter?.decrement(0) // 8 counter?.decrement(2) // 6 counter?.increment(-1) // 5 // Set the value of the MutableRealmInt property // ** Use set() with caution ** counter?.set(0)// 0 }
RealmAny(混合)プロパティの更新
RealmAnyプロパティは不変です。 RealmAny値を更新するには、目的の値とタイプを持つプロパティの新しいインスタンスを作成する必要があります。 RealmAnyプロパティの追加の詳細については、「 RealmAny(混合)プロパティの作成 」を参照してください。
さらに、 RealmAnyプロパティから値を抽出するには、保存された型を知っている必要があります。 間違った型で getter メソッドを呼び出すと、Realm は例外をスローします。
Tip
条件式による多形データの処理
その値を抽出するには、保存された型を知っている必要があるため、 RealmAny型とその可能な内部値クラスを処理するにはwhen式を使用することをお勧めします。
val favoriteThings = frog.favoriteThings when (favoriteThings.type) { INT -> rating(favoriteThings.asInteger()) STRING -> description(favoriteThings.asString()) BYTE_ARRAY -> image(favoriteThings.asByteArray()) // Handle other possible types... else -> { // Debug or a perform default action Log.d("ExampleHandler", "Unhandled type: ${favoriteThings.type}") } }
次の例では、各リスト要素の新しいインスタンスを作成して、 RealmAnyプロパティのリストを含むFrogオブジェクトをアップデートします。
// Find favoriteThing that is an Int // Convert the value to Double and update the favoriteThing property realm.write { val kermit = query<Frog>().find().first() val realmAny: RealmList<RealmAny?> = kermit.favoriteThings for (i in realmAny.indices) { val thing = realmAny[i] if (thing?.type == RealmAny.Type.INT) { val intValue = thing.asInt() val doubleValue = intValue.toDouble() realmAny[i] = RealmAny.create(doubleValue) } } } // Overwrite all existing favoriteThing properties // ** Null clears the property value ** realm.write { val frog = query<Frog>().find().first() val realmAny: RealmList<RealmAny?> = frog.favoriteThings realmAny[0] = RealmAny.create("sunshine") realmAny[1] = RealmAny.create(Frog().apply { name = "Kermit Sr." }) realmAny[2] = null }
注意
RealmAny プロパティ値を null でクリア
現在の値を削除するには、 nullをRealmAnyプロパティに直接割り当てます。
コレクション プロパティを更新
オブジェクトタイプの定義方法によっては、サポートされている次のコレクション タイプのいずれかとして定義されるプロパティがある場合があります。
RealmListRealmSetRealmDictionary
コレクションは可変であり、対応する組み込み Kotlin クラスによってサポートされています。 書込みトランザクション (write transaction) 内でコレクション内の要素を追加および削除できます。
RealmList の更新
RealmList 内の要素はKotlin MutableList と同様に更新できます。
次の例では、既存のFrogオブジェクトのRealmList要素をアップデートします。
realm.write { // Get the live object val realmList = query<Frog>("name = $0", "Kermit").first().find()!!.favoritePonds realmList[0].name = "Picnic Pond" realmList.set(1, Pond().apply { name = "Big Pond" }) }
RealmList要素の追加と削除の詳細については、「 RealmList の作成 」と「 RealmListからの要素の削除 」を参照してください。
RealmSet の更新
RealmSet ではKotlin MutableSet と同様に要素を追加、更新、削除できます。
次の例では、既存のFrogオブジェクトのRealmSet要素を反復処理して更新します。
// Find a frog in the realm val kermit = realm.query<Frog>("name = $0", "Kermit").find().first() val realmSet = kermit.favoriteSnacks // Update the name of each snack in the set for (snack in realmSet) { realm.write { findLatest(snack)?.name = snack.name.uppercase() } } realm.write { // Find all frogs who like rain val frogsWhoLikeRain = realm.query<Frog>("favoriteWeather CONTAINS $0", "rain").find() // Add thunderstorms to their favoriteWeather set for (frog in frogsWhoLikeRain) { val latestFrog = findLatest(frog) latestFrog?.favoriteWeather?.add("thunderstorms") } }
RealmSet要素の追加と削除の詳細については、「 RealmSet プロパティの作成 」と「 RealmSetからの要素の削除 」を参照してください。
辞書の更新
RealmDictionary ではKotlin MutableMap と同様にキーと値をアップデートできます。
次の例では、次を更新します: RealmDictionary
// Find frogs who have forests with favorite ponds val thisFrog = realm.query<RealmDictionary_Frog>("favoritePondsByForest.@count > 1").find().first() // Update the value for a key if it exists if (thisFrog.favoritePondsByForest.containsKey("Hundred Acre Wood")) { realm.write { findLatest(thisFrog)?.favoritePondsByForest?.set("Lothlorien", "Lily Pad Pond") } } // Add a new key-value pair realm.write { findLatest(thisFrog)?.favoritePondsByForest?.put("Sherwood Forest", "Miller Pond") }
RealmDictionaryエントリの追加と削除の詳細については、「 辞書プロパティの作成 」と「 辞書のキーと値の削除 」を参照してください。
関係の更新
オブジェクトタイプの定義方法によっては、別の Realm オブジェクトを参照するプロパティがある場合があります。 これは 1 対多、対多、または逆の関係にすることができます。
また、ある Realm オブジェクトを別の Realm オブジェクトに直接埋め込み、 EmbeddedRealmObjectタイプのネストされたデータ構造を作成することもできます。 詳細については、このページの「 埋め込みオブジェクトの更新」セクションを参照してください。
To1 の関係の更新
Realm 内のオブジェクト間の関係を更新するには、関係を定義するプロパティを他のプロパティと同様に変更します。
次の例では、単一のPondオブジェクトを参照するfavoritePondプロパティと、別のFrogオブジェクトを参照するbestFriendプロパティを持つFrogオブジェクトがあります。
realm.write { val kermit = query<Frog>("name == $0", "Kermit").find().first() // Update a property on the related object kermit.favoritePond?.name = "Big Pond" // Assign a new related object val newBestFriend = Frog().apply { name = "Froggy Jr." } kermit.bestFriend = newBestFriend }
ToMany 関係の更新
対多の関係は、他のコレクションと同様に更新できます。 このページの「コレクション プロパティの更新 」セクションを参照してください。
次の例では、 Frogオブジェクトのセットを参照するfrogsThatLiveHereプロパティと、 Pondオブジェクトのリストを参照するnearByPondsプロパティを持つForestオブジェクトがあります。
realm.write { val forest = query<Forest>().find().first() // Update a property on a related object in the set forest.frogsThatLiveHere.first().name = "Kermit Sr." // Add a new related object to the list forest.frogsThatLiveHere.add(Frog().apply { name = "Froggy Jr." }) }
逆の関係の更新
逆の関係でオブジェクトにアクセスしてアップデートできます。 ただし、バックリンク コレクション自体を直接変更することはできません。 代わりに、関連するオブジェクトを変更すると、Realm は暗黙的な関係を自動的に更新します。 詳しくは、「 逆の関係の定義 」を参照してください。
次の例では、親Userオブジェクトと、 Post子オブジェクトのリストを参照するバックリンクpostsプロパティがあります。 バックリンクを介して親オブジェクトと子オブジェクトのプロパティを更新します。
realm.write { // Update child objects through the parent val parent = query<User>().find().first() parent.posts[0].title = "Forest Life Vol. 2" parent.posts.add(Post().apply { title = "Forest Life Vol. 3" }) // Update child objects (Realm automatically updates the backlink collection) val child = query<Post>("title == $0", "Top Ponds of the Year!").find().first() child.title = "Top Ponds of the Year! Vol. 2" assertEquals("Top Ponds of the Year! Vol. 2", parent.posts[1].title) // Update the parent object through the child child.user[0].name = "Kermit Sr." // ** You CANNOT directly modify the backlink collection ** val readOnlyBacklink: RealmResults<User> = child.user }
Realm オブジェクトのアップサート
オブジェクトを Realm にアップサートするには、 copyToRealm()を使用してプライマリキーを持つオブジェクトを挿入し、 新しいオブジェクト を作成する場合と同様に、 UpdatePolicyパラメーターを渡して、SDK が同じプライマリキーを持つ既存のオブジェクトを処理する方法を指定します。
UpdatePolicy.ALL: 同じプライマリキーで識別される既存のオブジェクトのすべてのプロパティを更新します。UpdatePolicy.ERROR(デフォルト): 既存のオブジェクトのアップデートは許可されず、代わりに同じプライマリキーを持つオブジェクトがすでに存在する場合には例外がスローされます。 更新ポリシーを指定しない場合、Realm はデフォルトでこのポリシーを使用します。
更新ポリシーによっては、次のことが発生する可能性があります。
プライマリキーに一致するオブジェクトが存在しない場合、SDK は新しいオブジェクトを挿入します。
同じプライマリキーを持つオブジェクトがすでに存在する場合、SDK は次のいずれかになります。
同じプライマリキーで識別される既存のオブジェクトのすべてのプロパティを更新します。 プロパティが同じ値にアップデートされた場合でも、プロパティは変更リスナーでアップデートされたものとしてマークされることに注意してください。
オブジェクトが Realm にすでに存在することを示す例外をスローします。
次の例では、 UpdatePolicy.ALLを使用して、Realm にすでに存在するプライマリキーを持つFrogオブジェクトを挿入し、オブジェクトが正常にアップサートされていることを確認します。
realm.write { val existingFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first() assertEquals(existingFrog.name, "Kermit") // Use copyToRealm() to insert the object with the primary key // ** UpdatePolicy determines whether to update or throw an error if object already exists** copyToRealm(Frog().apply { _id = PRIMARY_KEY_VALUE name = "Wirt" age = 4 species = "Greyfrog" owner = "L'oric" }, UpdatePolicy.ALL) val upsertFrog = query<Frog>("_id == $0", PRIMARY_KEY_VALUE).find().first() assertEquals(upsertFrog.name, "Wirt") }