diff --git a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ReadTest.kt b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ReadTest.kt index 406db6eab2c..d46e209fb40 100644 --- a/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ReadTest.kt +++ b/examples/kotlin/shared/src/commonTest/kotlin/com/mongodb/realm/realmkmmapp/ReadTest.kt @@ -72,12 +72,20 @@ class ReadTest: RealmTest() { owner = "Jim Henson" }) } + // :snippet-start: basic-queries + val simpleQuery = realm.query() + val filteredQuery = realm.query("name == $0", "Kermit") + val chainedQuery = simpleQuery.query("owner == $0", "Jim Henson").query("age > 1") + val sortedQuery = chainedQuery.sort("age", Sort.DESCENDING) + // :snippet-end: // :snippet-start: read-realm-object // Pass the object type as a query parameter - val findFrogs = realm.query() - // Filter results + // and filter by property + val findFrogs = + realm.query("age > 1") + // Optionally, chain another query filter .query("owner == $0", "Jim Henson") - // Sort results + // Optionally, sort results by property .sort("age", Sort.ASCENDING) // Run the query .find() @@ -107,10 +115,9 @@ class ReadTest: RealmTest() { // :snippet-start: frozen-vs-live-results // 'Realm.query()' always returns frozen results val frozenResults = realm.query("age > $0", 50).find() - // If you try to modify the queried object, SDK throws 'IllegalStateException' - frozenResults.first().age += 1 - - // :remove-start: + // :remove-start: + // assert SDK throws 'IllegalStateException' + frozenResults.first().age += 1 } assertTrue( thrownException.message!!.contains("[RLM_ERR_WRONG_TRANSACTION_STATE]"), @@ -121,11 +128,11 @@ class ReadTest: RealmTest() { // Open a write transaction to access the MutableRealm realm.write { // this: MutableRealm val liveResults = this.query("age > $0", 50).find() - // You can modify queried object + // :snippet-end: + // assert you can modify queried object liveResults.first().age += 1 - assertEquals(102, liveResults.first().age) // :remove: + assertEquals(102, liveResults.first().age) } - // :snippet-end: realm.write { deleteAll() } realm.close() } @@ -170,9 +177,10 @@ class ReadTest: RealmTest() { // Calling 'asFlow()' on the query returns a ResultsChange Flow // Can ONLY be called on a `Realm.query()` val allFrogsFlow: Flow> = queryAllFrogs.asFlow() - val thrownException = assertFailsWith { // :remove: - val allLiveFrogsFlow: Flow> = queryAllLiveFrogs.asFlow() // throws exception - // :snippet-end: + // :snippet-end: + // assert SDK throws exception + val thrownException = assertFailsWith { + val allLiveFrogsFlow: Flow> = queryAllLiveFrogs.asFlow() } assertTrue(thrownException.message!!.contains("Observing changes are not supported by this Realm")) assertEquals(3, allFrogs.size) @@ -229,12 +237,13 @@ class ReadTest: RealmTest() { // :snippet-end: assertEquals("Jim Henson", singleFrog?.owner) // :snippet-start: find-by-primary-key - val queryByPrimaryKey = realm.query("_id == $0", PRIMARY_KEY_VALUE).find().first() + val filterByPrimaryKey = realm.query("_id == $0", PRIMARY_KEY_VALUE) + val findPrimaryKey = filterByPrimaryKey.find().first() // :snippet-end: - assertEquals(PRIMARY_KEY_VALUE, queryByPrimaryKey._id) + assertEquals(PRIMARY_KEY_VALUE, findPrimaryKey._id) // :snippet-start: query-by-property - val queryByProperty = realm.query("name == $0", "Kermit") - val frogsNamedKermit = queryByProperty.find() + val filterByProperty = realm.query("name == $0", "Kermit") + val frogsNamedKermit = filterByProperty.find() // :snippet-end: assertEquals(1, frogsNamedKermit.size) realm.write { deleteAll() } @@ -279,14 +288,14 @@ class ReadTest: RealmTest() { // :snippet-start: query-embedded-object-property // Use dot notation to access the embedded object properties as if it // were in a regular nested object - val queryEmbeddedObjectProperty = + val filterEmbeddedObjectProperty = realm.query("address.street == '123 Pond St'") - // You can also query properties nested within the embedded object + // You can also access properties nested within the embedded object val queryNestedProperty = realm.query() .query("address.propertyOwner.name == $0", "Mr. Frog") // :snippet-end: - val findEmbeddedObjectProperty = queryEmbeddedObjectProperty.find().first() + val findEmbeddedObjectProperty = filterEmbeddedObjectProperty.find().first() val findNestedProperty = queryNestedProperty.find().first() assertEquals("123 Pond St", findEmbeddedObjectProperty.address?.street) assertEquals("Mr. Frog", findNestedProperty.address?.propertyOwner?.name) @@ -316,8 +325,8 @@ class ReadTest: RealmTest() { } realm.write { // :snippet-start: query-realmany-property - val queryFrogLovesNumbers = realm.query("favoriteThing.@type == 'int'") - val findFrog = queryFrogLovesNumbers.find().first() + val filterByRealmAnyInt = realm.query("favoriteThing.@type == 'int'") + val findFrog = filterByRealmAnyInt.find().first() // :snippet-end: // :snippet-start: get-realmany-property val frogsFavoriteThing = findFrog.favoriteThing // Int @@ -325,15 +334,15 @@ class ReadTest: RealmTest() { // Using the correct getter method returns the value val frogsFavoriteNumber = frogsFavoriteThing?.asInt() println("${findFrog.name} likes the number $frogsFavoriteNumber") - assertEquals(42, frogsFavoriteNumber) // :remove: + // :snippet-end: + assertEquals(42, frogsFavoriteNumber) - val thrownException = assertFailsWith { // :remove: - // Using the wrong getter method throws an exception - val frogsFavoriteUUID = frogsFavoriteThing?.asRealmUUID() - // :snippet-end: + val thrownException = assertFailsWith { + // assert that wrong getter throws an exception + val frogsFavoriteUUID = frogsFavoriteThing?.asRealmUUID() } assertTrue(thrownException.message!!.contains("RealmAny type mismatch")) - val frogsFavoriteThings = queryFrogLovesNumbers.find().map { it.favoriteThing } + val frogsFavoriteThings = filterByRealmAnyInt.find().map { it.favoriteThing } // :snippet-start: polymorphism // Handle possible types with a 'when' statement frogsFavoriteThings.forEach { realmAny -> @@ -395,13 +404,18 @@ class ReadTest: RealmTest() { }) } // :snippet-start: query-remapped-property - val queryKotlinName = realm.query("species == $0", "Muppetarium Amphibius").find().first() - val queryRemappedName = realm.query("latin_name == $0", "Muppetarium Amphibius").find().first() + val filterByKotlinName = realm.query("species == $0", "Muppetarium Amphibius") + val findSpecies = filterByKotlinName.find().first() + + val filterByRemappedName = realm.query("latin_name == $0", "Muppetarium Amphibius") + val find_latin_name = filterByRemappedName.find().first() // Both queries return the same object - assertEquals(queryKotlinName, queryRemappedName) + assertEquals(findSpecies, find_latin_name) // :snippet-end: // :snippet-start: query-fts-property + // Filter by FTS property value using 'TEXT' + // Find all frogs with "green" in the physical description val onlyGreenFrogs = realm.query("physicalDescription TEXT $0", "green").find() @@ -498,8 +512,9 @@ class ReadTest: RealmTest() { } realm.write { // :snippet-start: read-realm-set - // Find frogs who have a favorite snack of flies and crickets - val potentialFrogs = query("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets").find() + // Find frogs with flies and crickets as a favorite snack + val filterBySnackSet = query("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets") + val potentialFrogs = filterBySnackSet.find() // Check if the set contains a value val frogsThatLikeWorms = potentialFrogs.filter { frog -> @@ -608,10 +623,10 @@ class ReadTest: RealmTest() { // Find all forests with at least one nearby pond val allForests = query().find() val forestsWithPonds = allForests.query("nearbyPonds.@count > $0", 0).find() - val bigPond = query("name == $0", "Big Pond").find().first() // Iterate through the results for (forest in forestsWithPonds) { + val bigPond = query("name == $0", "Big Pond").find().first() if (forest.nearbyPonds.contains(bigPond)) { Log.v("${forest.name} has a nearby pond named ${bigPond.name}") } else { @@ -652,21 +667,24 @@ class ReadTest: RealmTest() { } realm.write { val today = RealmInstant.now() - //RealmInstant.from(1677628500, 0) // Feb 28 2023 // :snippet-start: query-inverse-relationship - // Query the parent object to access the child objects - val user = query("name == $0", "Kermit").find().first() - val myFirstPost = user.posts[0] + // Query the parent object + val filterByUserName = query("name == $0", "Kermit") + val kermit = filterByUserName.find().first() + + // Use dot notation to access child objects + val myFirstPost = kermit.posts[0] assertEquals("Forest Life", myFirstPost.title) // :remove: // Iterate through the backlink collection property - user.posts.forEach { post -> - Log.v("${user.name}'s Post: ${post.date} - ${post.title}") + kermit.posts.forEach { post -> + Log.v("${kermit.name}'s Post: ${post.date} - ${post.title}") } - // Query the backlink with `@links..` - val oldPostsByKermit = realm.query() - .query("@links.ExampleRelationship_User.posts.name == $0 AND date < $1", "Kermit", today) + // Filter posts through the parent's backlink property + // using `@links..` syntax + val oldPostsByKermit = realm.query("date < $1", today) + .query("@links.ExampleRelationship_User.posts.name == $0", "Kermit") .find() assertEquals(2, oldPostsByKermit.size) // :remove: @@ -675,7 +693,7 @@ class ReadTest: RealmTest() { val post2 = query("title == $0", "Top Ponds of the Year!").find().first() val parent = post1.user.first() // :snippet-end: - assertTrue(user.posts.containsAll(listOf(post1, post2))) + assertTrue(kermit.posts.containsAll(listOf(post1, post2))) assertEquals("Kermit", parent.name) deleteAll() } @@ -717,7 +735,8 @@ class ReadTest: RealmTest() { copyToRealm(user) } // :snippet-start: query-inverse-persisted-name - // Query by the remapped name 'Blog_Author' + // Filter by the remapped object type name + // using `@links..` syntax val postsByKermit = realm.query() .query("@links.Blog_Author.posts.name == $0", "Kermit") .find() @@ -756,7 +775,7 @@ class ReadTest: RealmTest() { } // :snippet-start: sort-results // Query for all frogs owned by Jim Henson, then: - // 1. Sort the results by age in descending order + // 1. Sort results by age in descending order // 2. Limit results to only distinct names // 3. Limit results to only the first 2 objects diff --git a/source/examples/generated/kotlin/ReadTest.snippet.basic-queries.kt b/source/examples/generated/kotlin/ReadTest.snippet.basic-queries.kt new file mode 100644 index 00000000000..bb57dbfb6aa --- /dev/null +++ b/source/examples/generated/kotlin/ReadTest.snippet.basic-queries.kt @@ -0,0 +1,4 @@ +val simpleQuery = realm.query() +val filteredQuery = realm.query("name == $0", "Kermit") +val chainedQuery = simpleQuery.query("owner == $0", "Jim Henson").query("age > 1") +val sortedQuery = chainedQuery.sort("age", Sort.DESCENDING) diff --git a/source/examples/generated/kotlin/ReadTest.snippet.find-by-primary-key.kt b/source/examples/generated/kotlin/ReadTest.snippet.find-by-primary-key.kt index a786949ea8f..cd97bb20914 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.find-by-primary-key.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.find-by-primary-key.kt @@ -1 +1,2 @@ -val queryByPrimaryKey = realm.query("_id == $0", PRIMARY_KEY_VALUE).find().first() +val filterByPrimaryKey = realm.query("_id == $0", PRIMARY_KEY_VALUE) +val findPrimaryKey = filterByPrimaryKey.find().first() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt b/source/examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt index 34f582ab0d3..1e0adf2e204 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt @@ -1,12 +1,6 @@ // 'Realm.query()' always returns frozen results val frozenResults = realm.query("age > $0", 50).find() -// If you try to modify the queried object, SDK throws 'IllegalStateException' -frozenResults.first().age += 1 - // 'MutableRealm.query()' returns live results // Open a write transaction to access the MutableRealm realm.write { // this: MutableRealm val liveResults = this.query("age > $0", 50).find() - // You can modify queried object - liveResults.first().age += 1 -} diff --git a/source/examples/generated/kotlin/ReadTest.snippet.get-realmany-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.get-realmany-property.kt index 455bfb561fe..0e7585bf290 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.get-realmany-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.get-realmany-property.kt @@ -3,6 +3,3 @@ val frogsFavoriteThing = findFrog.favoriteThing // Int // Using the correct getter method returns the value val frogsFavoriteNumber = frogsFavoriteThing?.asInt() println("${findFrog.name} likes the number $frogsFavoriteNumber") - -// Using the wrong getter method throws an exception -val frogsFavoriteUUID = frogsFavoriteThing?.asRealmUUID() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-by-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-by-property.kt index 020a103401d..16258eb7e44 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-by-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-by-property.kt @@ -1,2 +1,2 @@ -val queryByProperty = realm.query("name == $0", "Kermit") -val frogsNamedKermit = queryByProperty.find() +val filterByProperty = realm.query("name == $0", "Kermit") +val frogsNamedKermit = filterByProperty.find() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-embedded-object-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-embedded-object-property.kt index c6e46996d23..62183931a15 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-embedded-object-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-embedded-object-property.kt @@ -1,8 +1,8 @@ // Use dot notation to access the embedded object properties as if it // were in a regular nested object -val queryEmbeddedObjectProperty = +val filterEmbeddedObjectProperty = realm.query("address.street == '123 Pond St'") -// You can also query properties nested within the embedded object +// You can also access properties nested within the embedded object val queryNestedProperty = realm.query() .query("address.propertyOwner.name == $0", "Mr. Frog") diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-fts-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-fts-property.kt index 0d00b96c466..26dde5d45b1 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-fts-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-fts-property.kt @@ -1,3 +1,5 @@ +// Filter by FTS property value using 'TEXT' + // Find all frogs with "green" in the physical description val onlyGreenFrogs = realm.query("physicalDescription TEXT $0", "green").find() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-persisted-name.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-persisted-name.kt index 1a8141f9cf6..3993d6fe6a4 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-persisted-name.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-persisted-name.kt @@ -1,4 +1,5 @@ -// Query by the remapped name 'Blog_Author' +// Filter by the remapped object type name +// using `@links..` syntax val postsByKermit = realm.query() .query("@links.Blog_Author.posts.name == $0", "Kermit") .find() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-relationship.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-relationship.kt index 32954f2b397..9bded98d4dd 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-relationship.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-inverse-relationship.kt @@ -1,15 +1,19 @@ -// Query the parent object to access the child objects -val user = query("name == $0", "Kermit").find().first() -val myFirstPost = user.posts[0] +// Query the parent object +val filterByUserName = query("name == $0", "Kermit") +val kermit = filterByUserName.find().first() + +// Use dot notation to access child objects +val myFirstPost = kermit.posts[0] // Iterate through the backlink collection property -user.posts.forEach { post -> - Log.v("${user.name}'s Post: ${post.date} - ${post.title}") +kermit.posts.forEach { post -> + Log.v("${kermit.name}'s Post: ${post.date} - ${post.title}") } -// Query the backlink with `@links..` -val oldPostsByKermit = realm.query() - .query("@links.User.posts.name == $0 AND date < $1", "Kermit", today) +// Filter posts through the parent's backlink property +// using `@links..` syntax +val oldPostsByKermit = realm.query("date < $1", today) + .query("@links.User.posts.name == $0", "Kermit") .find() // Query the child object to access the parent diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-realmany-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-realmany-property.kt index 9c3ee128ef6..49e6e0ba1cc 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-realmany-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-realmany-property.kt @@ -1,2 +1,2 @@ -val queryFrogLovesNumbers = realm.query("favoriteThing.@type == 'int'") -val findFrog = queryFrogLovesNumbers.find().first() +val filterByRealmAnyInt = realm.query("favoriteThing.@type == 'int'") +val findFrog = filterByRealmAnyInt.find().first() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-remapped-property.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-remapped-property.kt index 2e6fa2d4d60..dfd00575806 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-remapped-property.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-remapped-property.kt @@ -1,5 +1,8 @@ -val queryKotlinName = realm.query("species == $0", "Muppetarium Amphibius").find().first() -val queryRemappedName = realm.query("latin_name == $0", "Muppetarium Amphibius").find().first() +val filterByKotlinName = realm.query("species == $0", "Muppetarium Amphibius") +val findSpecies = filterByKotlinName.find().first() + +val filterByRemappedName = realm.query("latin_name == $0", "Muppetarium Amphibius") +val find_latin_name = filterByRemappedName.find().first() // Both queries return the same object -assertEquals(queryKotlinName, queryRemappedName) +assertEquals(findSpecies, find_latin_name) diff --git a/source/examples/generated/kotlin/ReadTest.snippet.query-to-many-relationship.kt b/source/examples/generated/kotlin/ReadTest.snippet.query-to-many-relationship.kt index b986c331659..727a8842f1b 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.query-to-many-relationship.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.query-to-many-relationship.kt @@ -1,10 +1,10 @@ // Find all forests with at least one nearby pond val allForests = query().find() val forestsWithPonds = allForests.query("nearbyPonds.@count > $0", 0).find() -val bigPond = query("name == $0", "Big Pond").find().first() // Iterate through the results for (forest in forestsWithPonds) { + val bigPond = query("name == $0", "Big Pond").find().first() if (forest.nearbyPonds.contains(bigPond)) { Log.v("${forest.name} has a nearby pond named ${bigPond.name}") } else { diff --git a/source/examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt b/source/examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt index 241529f5c18..f46eb821737 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt @@ -1,8 +1,10 @@ // Pass the object type as a query parameter -val findFrogs = realm.query() - // Filter results +// and filter by property +val findFrogs = + realm.query("age > 1") + // Optionally, chain another query filter .query("owner == $0", "Jim Henson") - // Sort results + // Optionally, sort results by property .sort("age", Sort.ASCENDING) // Run the query .find() diff --git a/source/examples/generated/kotlin/ReadTest.snippet.read-realm-set.kt b/source/examples/generated/kotlin/ReadTest.snippet.read-realm-set.kt index ba4ea63e894..2f1e73c0d1c 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.read-realm-set.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.read-realm-set.kt @@ -1,5 +1,6 @@ -// Find frogs who have a favorite snack of flies and crickets -val potentialFrogs = query("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets").find() +// Find frogs with flies and crickets as a favorite snack +val filterBySnackSet = query("favoriteSnacks.name CONTAINS $0 AND favoriteSnacks.name CONTAINS $1", "Flies", "Crickets") +val potentialFrogs = filterBySnackSet.find() // Check if the set contains a value val frogsThatLikeWorms = potentialFrogs.filter { frog -> diff --git a/source/examples/generated/kotlin/ReadTest.snippet.sort-results.kt b/source/examples/generated/kotlin/ReadTest.snippet.sort-results.kt index ac8db7bb935..cc791d801ca 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.sort-results.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.sort-results.kt @@ -1,5 +1,5 @@ // Query for all frogs owned by Jim Henson, then: -// 1. Sort the results by age in descending order +// 1. Sort results by age in descending order // 2. Limit results to only distinct names // 3. Limit results to only the first 2 objects diff --git a/source/examples/generated/kotlin/ReadTest.snippet.synchronous-query.kt b/source/examples/generated/kotlin/ReadTest.snippet.synchronous-query.kt index 240e28b136a..d4eadb137a5 100644 --- a/source/examples/generated/kotlin/ReadTest.snippet.synchronous-query.kt +++ b/source/examples/generated/kotlin/ReadTest.snippet.synchronous-query.kt @@ -9,4 +9,3 @@ val allLiveFrogs: RealmResults = queryAllLiveFrogs.find() // Calling 'asFlow()' on the query returns a ResultsChange Flow // Can ONLY be called on a `Realm.query()` val allFrogsFlow: Flow> = queryAllFrogs.asFlow() -val allLiveFrogsFlow: Flow> = queryAllLiveFrogs.asFlow() // throws exception diff --git a/source/sdk/kotlin/realm-database/crud/read.txt b/source/sdk/kotlin/realm-database/crud/read.txt index b2fd3d08625..d016588e408 100644 --- a/source/sdk/kotlin/realm-database/crud/read.txt +++ b/source/sdk/kotlin/realm-database/crud/read.txt @@ -16,96 +16,65 @@ Read Realm Objects - Kotlin SDK .. contents:: On this page :local: :backlinks: none - :depth: 3 + :depth: 4 :class: singlecol This page describes how to query and read objects persisted in a database -with the Atlas Device SDK for Kotlin. To learn how to modify queried objects, -refer to :ref:`kotlin-update-objects`. To learn how to observe -changes to queried objects, refer to :ref:`kotlin-query-change-listener`. +with the Atlas Device SDK for Kotlin. Atlas Device SDKs lazily evaluate query results, enabling you to write elegant, +highly performant code for handling large data sets and complex queries. -.. note:: +.. note:: Cannot Read Asymmetric Objects - The page demonstrates querying using Realm Query Language - (RQL), but it is not an exhaustive guide. For in-depth information on RQL, - its operators, and constructing queries, refer to :ref:``. - -The standard data access pattern across Atlas Device SDK is to find, -filter, and sort database objects that you want to read, then the SDK lazily -evaluates the results. This lazy evaluation enables you to write elegant, -highly performant code for handling large data sets and complex queries. -This also means that you can chain several queries together without a separate -trip to the database for each successive query. + You *cannot* read asymmetric objects because they are special + write-only objects that do not persist to the database. For information on + how to use asymmetric objects in your application, refer to + :ref:`kotlin-stream-data-to-atlas`. Read Operations --------------- -You can perform read operations in a synced or non-synced database using the -SDK's query builder -`RealmQuery <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/index.html>`__. +A read operation consists of querying database objects, then running the query when you're ready to access the results. The syntax for read operations is the same for synced and non-synced databases. -All queries are based on :ref:`object type `. You can -query any objects, including :ref:`embedded objects `, -that persist to the database and whose type is included in your database schema. -This means that you *cannot* read asymmetric objects, which are special -write-only objects that do not persist to the database. For information on -how to use asymmetric objects in your application, refer to -:ref:`kotlin-stream-data-to-atlas`. +Query, Filter, and Sort +~~~~~~~~~~~~~~~~~~~~~~~ -.. example:: Read Operation +All queries are based on :ref:`object type `. +You can query any object, including :ref:`embedded objects `, +that persist to the database and whose type is included in your :ref:`database schema `. - .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt - :language: kotlin +Construct queries using the SDK's query builder +`RealmQuery <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/index.html>`__, passing the object type as the type parameter. A ``RealmQuery`` can query on a ``Realm`` or ``MutableRealm`` instance, a ``RealmResults`` +collection, or a ``RealmList`` collection. -You can query a ``Realm`` or ``MutableRealm`` instance, a ``RealmResults`` -collection, or a ``RealmList`` collection. And unlike other Atlas Device SDKs, -which always return live results, the SDK for Kotlin can return both frozen and -live results. +A basic ``RealmQuery`` returns all objects of the specified type: -The SDK *always* returns **frozen results** when you run a query on a -`Realm <{+kotlin-local-prefix+}io.realm.kotlin/-realm/query.html>`__. Frozen -results cannot be modified and do not reflect the latest changes to the -database. And because you can access a ``Realm`` inside or outside of a write -transaction, a ``Realm.query()`` does not require a write transaction. +.. code:: kotlin -To return **live results**, you must run a query on a -`MutableRealm <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/index.html>`__ -instance. A ``MutableRealm`` represents a writeable state of a database and -is *only* accessible through a write transaction. Results from a -`MutableRealm.query <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/query.html>`__ -are live, but are only valid on the calling thread and are frozen once the -write transaction completes. -You can also return live objects from frozen results by calling -`MutableRealm.findLatest() <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/find-latest.html>`__ . -For more information, refer to the :ref:`kotlin-find-latest-version` section -on this page. + .query() // Finds all objects of type -For more information on write transactions and accessing a ``MutableRealm``, -refer to :ref:``. +You can refine your query with additional filters and conditions using **Realm Query Language (RQL)**, a string-based query language, in combination with +built-in Kotlin extension functions and helper methods provided by the SDK. -.. example:: Access Live Results +You can filter and sort by property: - .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt - :language: kotlin +.. code:: kotlin -Filter and Sort -~~~~~~~~~~~~~~~ + .query(filter) // Finds all objects of type that meet the filter conditions -By default, the SDK returns all objects of the object type passed as a query -parameter. To further refine and sort results, you can pass filters and -additional operators using **Realm Query Language (RQL)**. +You can also **chain queries** together. And because of the SDK's lazy evaluation, successive queries do not require separate +trips to the database. -RQL is a robust string-based query language that you can use to retrieve -specific objects from a database. It can also be used in combination with -built-in Kotlin extension functions and helper methods provided by the SDK. -For in-depth information on querying with RQL, refer to :ref:``. +.. example:: Basic Query + + .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.basic-queries.kt + :language: kotlin Run the Query ~~~~~~~~~~~~~ When you're ready to access the data and work with the returned results, -you can run the query: +run the query: - Use `find() <{+kotlin-local-prefix+}io.realm.kotlin.query/find.html>`__ to perform a **synchronous query**. The SDK lazily returns a @@ -133,6 +102,38 @@ of a query. .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.synchronous-query.kt :language: kotlin +Frozen and Live Results +~~~~~~~~~~~~~~~~~~~~~~~ + +Unlike other Atlas Device SDKs, +which always return live results, the Kotlin SDK can return both frozen and +live results. For more information on the Kotlin SDK's frozen architecture, refer to :ref:`kotlin-frozen-architecture`. + +To access **frozen results**, run a query on a +`Realm <{+kotlin-local-prefix+}io.realm.kotlin/-realm/query.html>`__. Frozen +results cannot be modified and do not reflect the latest changes to the +database. A ``Realm.query()`` does not require a write transaction. + +To access **live results**, run a query on a +`MutableRealm <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/index.html>`__ +instance in a write transaction. A ``MutableRealm`` represents a writeable state of a database and +is *only* accessible through a write transaction. Results from a +`MutableRealm.query <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/query.html>`__ +are live, but are only valid on the calling thread and are frozen once the +write transaction completes. +For more information on write transactions and accessing a ``MutableRealm``, +refer to :ref:``. + +You can also access live objects from frozen results by calling +`MutableRealm.findLatest() <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/find-latest.html>`__ . +For more information, refer to the :ref:`kotlin-find-latest-version` section +on this page. + +.. example:: Access Live Results + + .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.frozen-vs-live-results.kt + :language: kotlin + Find Database Objects --------------------- @@ -142,15 +143,10 @@ To find objects stored within a database: `query() <{+kotlin-local-prefix+}io.realm.kotlin.ext/query.html>`__. The object type must already be included in your database schema. -#. Pass any queries to further filter the results. You can append - additional filters with - `query() <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/query.html>`__. - If you don't specify a query filter, the SDK returns all objects of the - specified type. - -#. Specify the sort order for the results. Because the database is unordered, - if you don't include a sort order, the SDK cannot guarantee the query returns - objects in any specific order. +#. Optionally, pass additional conditions to further refine the results: + + - Specify a filter to only return objects that meet the condition. If you don't specify a filter, the SDK returns all objects of the specified type. You can chain filters by appending `query() <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-query/query.html>`__. + - Specify the sort order for the results. Because the database is unordered, if you don't include a sort order, the SDK cannot guarantee the query returns objects in any specific order. #. Execute the query using either: @@ -159,17 +155,22 @@ To find objects stored within a database: - `asFlow() <{+kotlin-local-prefix+}io.realm.kotlin.query/-realm-element-query/as-flow.html>`__ f or asynchronous queries. Subscribes to a ``Flow`` of results changes. - .. tip:: Avoid ``find()`` on the UI Thread + .. tip:: Prefer ``asFlow()`` for Large Data Sets ``find()`` runs a synchronous query on the thread it is called from. - As a result, avoid using ``find()`` on the UI thread or in logic that + As a result, avoid using ``find()`` for large data sets on the UI thread or in logic that could delay the UI thread. - Prefer ``asFlow()`` to prevent performance impacts. + Prefer ``asFlow()`` to prevent negative performance or UI impact. #. Work with the results. Objects may be frozen or live, depending on the type of query you ran. +.. example:: Read Operation + + .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.read-realm-object.kt + :language: kotlin + .. _kotlin-find-latest-version: Find Latest Version of an Object @@ -178,15 +179,14 @@ Find Latest Version of an Object Because of the SDK's frozen architecture, you aren't always working with the latest version of an object or collection. -To find the latest version of an object or collection, you can call +To get a version of an object or collection that reflects the latest changes to the database, you can call `findLatest() <{+kotlin-local-prefix+}io.realm.kotlin/-mutable-realm/find-latest.html>`__ -from a ``MutableRealm`` instance. This method returns a live copy of the -object or collection that reflects the latest changes to the database. -Like a ``MutableRealm.query()``, results are only valid on the calling thread +from a ``MutableRealm`` instance. +Like a ``MutableRealm.query()``, the results are live *but* are only valid on the calling thread and are frozen once the write transaction completes. In the following example, we find the latest version of an existing -``frozenFrogs`` query's results collection, then modify the now-live objects: +``frozenFrogs`` query's results collection, then modify the now-live objects within the write transaction: .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.find-latest-version.kt :language: kotlin @@ -249,18 +249,32 @@ object: .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.query-single-object.kt :language: kotlin +Filter By Property +~~~~~~~~~~~~~~~~~~ + +You can filter a query by any property in the object type that persists in the database. This includes child properties, which you can refer to using dot notation. + +To filter by property, you can pass Realm Query Language (RQL) filters and operators, use Kotlin's built-in extension methods or the SDK's convenience methods, or use a combination thereof. +For information on all currently supported RQL operators and syntax, refer to the :ref:`` reference documentation. + +In the following example, we query a ``Frog`` object type and filter by the ``name`` +property: + +.. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.query-by-property.kt + :language: kotlin + .. _kotlin-find-by-primary-key: -Query By Primary Key -~~~~~~~~~~~~~~~~~~~~ +Filter By Primary Key +````````````````````` :ref:`Primary keys ` are unique identifiers for objects in a database, which makes them useful for querying specific objects. -To find an object with a specific primary key, pass the object type as a type +To filter by a specific primary key, pass the object type as a type parameter and query the primary key field for the desired value. -In the following example, we query a ``Frog`` object by the primary key field ``_id``: +In the following example, we query a ``Frog`` object and filter by the primary key property ``_id``: .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.find-by-primary-key.kt :language: kotlin @@ -272,24 +286,10 @@ In the following example, we query a ``Frog`` object by the primary key field `` objects have a primary key named ``_id``. For more information, refer to :ref:``. -Query By Property -~~~~~~~~~~~~~~~~~ - -You can query by any property in the object type that persists in the database. -You can also use dot notation to refer to child properties of an object. -For information on using dot notation with RQL, refer to -:ref:``. - -In the following example, we query a ``Frog`` object type by the ``name`` -property: - -.. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.query-by-property.kt - :language: kotlin - .. _kotlin-query-embedded-object-property: -Query an Embedded Object Property -````````````````````````````````` +Filter By Embedded Object Property +`````````````````````````````````` :ref:`Embedded objects ` act as nested data inside of a single specific parent object. You can query an embedded object directly or @@ -298,7 +298,7 @@ object directly, refer to the :ref:`kotlin-query-all-objects-of-type` section on this page. To find an embedded object through its parent object, pass the parent object -type as a type parameter and query the embedded object property using dot +type as a type parameter and filter by the embedded object property using dot notation. In the following example, we have a ``Contact`` parent object that contains an @@ -310,8 +310,8 @@ type against the embedded object's ``address.street`` property: .. _kotlin-query-realmany: -Query a RealmAny (Mixed) Property -````````````````````````````````` +Filter By RealmAny (Mixed) Property +``````````````````````````````````` A :ref:`kotlin-realmany` property represents a polymorphic value that can hold any one of its supported data types at a particular moment. You can query @@ -324,10 +324,12 @@ In the following example, we query a ``RealmAny`` property called :language: kotlin Unlike other properties, you must extract a ``RealmAny`` property's stored -value. You can return the currently stored type using +value before you can work with it. To extract the value, use +the SDK's getter method for the stored type. If you use the wrong getter for the type, the SDK throws an exception. + +You can use a conditional expression to get the currently stored type with `RealmAny.type() <{+kotlin-local-prefix+}io.realm.kotlin.types/-realm-any/type.html>`__, -then extract the value using the getter method for that type. If you use the -wrong getter method, the SDK throws an exception. For a full list of getter +then extract the value based on the type. For a full list of getter methods, refer to the `RealmAny <{+kotlin-local-prefix+}io.realm.kotlin.types/-realm-any/index.html>`__ API reference. @@ -355,13 +357,13 @@ would another value of that type. ``Byte``, ``Char``, ``Int``, ``Long``, and ``Short`` values are converted internally to ``int64_t`` values. Keep this in mind when comparing, sorting, or aggregating ``RealmAny`` values of these types. - -Query a Remapped Property -````````````````````````` + +Filter By Remapped Property +``````````````````````````` If your data model includes -:ref:`remapped property names `, you can query by -both the Kotlin name used in your code and the remapped name that's persisted +:ref:`remapped property names `, you can filter by +both the Kotlin property name used in your code and the remapped property name that's persisted in the database. In the following example, the ``Frog`` object has a property named ``species`` @@ -370,7 +372,7 @@ in the code that is remapped to ``latin_name`` in the database: .. literalinclude:: /examples/generated/kotlin/Schema.snippet.define-persisted-name.kt :language: kotlin -In the database, we can then query using both property names and return the same +In the database, we can filter by either property name and return the same results: .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.query-remapped-property.kt @@ -378,13 +380,14 @@ results: .. _kotlin-filter-fts: -Query a Full-Text Search (FTS) Property -``````````````````````````````````````` +Filter By Full-Text Search (FTS) Property +````````````````````````````````````````` + .. versionchanged:: 1.11.0 Support for prefix wildcard searches If your data model includes a :ref:`Full-Text Search (FTS) ` -index property, you can query the property with the ``TEXT`` predicate. +index property, you can filter by the property with the ``TEXT`` predicate. Words in the query are converted to tokens by a tokenizer using the following rules: @@ -409,13 +412,13 @@ The SDK returns a Boolean match for the specified query, instead of a relevance-based match. In the following example, the ``Frog`` object type has an FTS index property -called ``physicalDescription`` that we can query to find different types of frogs: +called ``physicalDescription`` that we can filter by to find different types of frogs: .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.query-fts-property.kt :language: kotlin -Query a Collection Property -``````````````````````````` +Filter By Collection Property +````````````````````````````` Depending on how you define your object type, you might have properties that are defined as one of the following supported :ref:``: @@ -468,14 +471,14 @@ In the following example, we query a ``RealmDictionary`` property called .. literalinclude:: /examples/generated/kotlin/ReadTest.snippet.read-realm-dictionary.kt :language: kotlin -Query a Relationship -```````````````````` +Filter By Relationship Property +``````````````````````````````` Depending on how you define your object type, you might have properties that reference another database object. This can be a to-one, to-many, or inverse :ref:`relationship `. -For information on querying relationship properties that reference an +For information on filtering by relationship properties that reference an :ref:`embedded object `, refer to the :ref:`` section on this page. @@ -483,7 +486,7 @@ To-One Relationships ++++++++++++++++++++ A :ref:`to-one relationship ` property maps to -a single instance of another object type. You can query the relationship +a single instance of another object type. You can filter by the relationship property using dot notation, the same way you would a nested object. In the following example, the ``Frog`` object type has a property called @@ -497,7 +500,7 @@ To-Many Relationships :ref:`To-many relationships ` properties are collections (a :ref:`RealmList ` or -:ref:`RealmSet `) of another object type. You can query +:ref:`RealmSet `) of another object type. You can filter by and iterate through the relationship property the same way you would any other collection property. @@ -555,10 +558,6 @@ you can find all coffee shops (objects with embedded coordinates) within 15 km of a location (the defined geodata region). The format for querying geospatial data is the same, regardless of the shape of the geodata region. -.. important:: - - You *cannot* use parameterized queries with geospatial data. - In the following example, we have a ``Company`` object type with an embedded object property called ``location``. We also have two defined geodata regions of type ``Geocircle``.