diff --git a/examples/dart/test/backlinks_test.dart b/examples/dart/test/backlinks_test.dart index bdafd65461b..aaf3dd81887 100644 --- a/examples/dart/test/backlinks_test.dart +++ b/examples/dart/test/backlinks_test.dart @@ -31,13 +31,13 @@ class _Task { // :snippet-end: void main() { - test('Filter Backlinks with RQL', () { + test('Query Inverse Backlinks', () { final config = Configuration.local([User.schema, Task.schema]); final realm = Realm(config); final han = User(ObjectId(), 'han', tasks: [ Task(ObjectId(), 'Pay Chewie back', false), - Task(ObjectId(), 'Get a haircut', true) + Task(ObjectId(), 'Get a haircut', false) ]); realm.write(() => realm.add(han)); final jarjar = User(ObjectId(), 'jarjar_binks', tasks: [ @@ -48,20 +48,39 @@ void main() { realm.write(() => realm.add(jarjar)); // :snippet-start: filter-backlinks-rql - // Filter tasks through the User's backlink property + // Filter Tasks through the User's backlink property // using `@links..` syntax final jarjarsIncompleteTasks = realm.query( "ALL @links.User.tasks.username == 'jarjar_binks' AND isComplete == false"); - final tasksForHan = realm.query("ALL @links.User.tasks.username == 'han'"); + final tasksForHan = + realm.query("ALL @links.User.tasks.username == 'han'"); // :snippet-end: expect(jarjarsIncompleteTasks.length, 2); expect(tasksForHan.length, 2); + + // :snippet-start: query-backlink-inverse-relationship + // Tasks have an inverse relationship to Users + final inCompleteTasks = realm.query("isComplete == false"); + + // Find all Users who have an incomplete Task + for (final task in inCompleteTasks) { + final ownersWithIncompleteTasks = task.getBacklinks('tasks'); + for (final user in ownersWithIncompleteTasks) { + print("User ${user.username} has incomplete tasks."); + } + } + // :snippet-end: + expect( + inCompleteTasks + .any((element) => element.description == 'Get a haircut'), + true); + cleanUpRealm(realm); }); - test('Query Backlinks', () { + test('Query To-One Backlinks', () { // Use to-one models from Schemas.dart final config = Configuration.local([Person.schema, Bike.schema]); final realm = Realm(config); @@ -78,10 +97,11 @@ void main() { realm.add(Bike(ObjectId(), 'Speeder Bike', owner: owner)); }); - // :snippet-start: query-backlinks + // :snippet-start: query-backlink-to-one-relationship + // Persons have a to-one relationship with Bikes final person = realm.query("firstName == 'Anakin'").first; - // Find all bikes that have an owner named Anakin + // Find all Bikes that have an Owner named 'Anakin' final allBikes = person.getBacklinks('owner'); // :snippet-end: expect(allBikes.length, 2); @@ -89,4 +109,40 @@ void main() { expect(allBikes.any((element) => element.owner!.id == ownerId), true); cleanUpRealm(realm); }); + + test('Query To-Many Backlinks', () { + // Use to-many models from Schemas.dart + final config = Configuration.local( + [Scooter.schema, ScooterShop.schema, Person.schema]); + final realm = Realm(config); + + final scooterId = ObjectId(); + final shopId = ObjectId(); + + realm.write(() { + Scooter roadHog = realm.add(Scooter(ObjectId(), 'Road Hog 9000')); + Scooter scooterbug = realm.add(Scooter(scooterId, 'Scooterbug')); + Scooter bigBen = realm.add(Scooter(ObjectId(), 'Big Ben')); + + realm.add(ScooterShop(ObjectId(), 'The Scoot Zone', + scooters: [roadHog, bigBen, scooterbug])); + + realm.add( + ScooterShop(ObjectId(), 'Scooterz', scooters: [scooterbug, bigBen])); + + realm.add(ScooterShop(shopId, 'Scoot n Shop', scooters: [roadHog])); + }); + // :snippet-start: query-backlinks-to-many-relationship + // Scooters have a to-many relationship with ScooterShops + final scooters = realm.query("name == 'Scooterbug'").first; + + // Find all ScooterShops that sell the Scooterbug + final shops = scooters.getBacklinks('scooters'); + + // :snippet-end: + expect(shops.length, 2); + expect(scooters.id, scooterId); + expect(shops.any((element) => element.id == shopId), false); + cleanUpRealm(realm); + }); } diff --git a/examples/dart/test/schemas.dart b/examples/dart/test/schemas.dart index a5530007169..ce3cda9128f 100644 --- a/examples/dart/test/schemas.dart +++ b/examples/dart/test/schemas.dart @@ -64,7 +64,7 @@ class _ScooterShop { late ObjectId id; late String name; - late List<_Scooter> owner; + late List<_Scooter> scooters; } // :snippet-end: diff --git a/examples/dart/test/schemas.g.dart b/examples/dart/test/schemas.g.dart index d7bdd2c3882..dbd6dcd33f7 100644 --- a/examples/dart/test/schemas.g.dart +++ b/examples/dart/test/schemas.g.dart @@ -256,12 +256,12 @@ class ScooterShop extends _ScooterShop ScooterShop( ObjectId id, String name, { - Iterable owner = const [], + Iterable scooters = const [], }) { RealmObjectBase.set(this, 'id', id); RealmObjectBase.set(this, 'name', name); RealmObjectBase.set>( - this, 'owner', RealmList(owner)); + this, 'scooters', RealmList(scooters)); } ScooterShop._(); @@ -277,10 +277,10 @@ class ScooterShop extends _ScooterShop set name(String value) => RealmObjectBase.set(this, 'name', value); @override - RealmList get owner => - RealmObjectBase.get(this, 'owner') as RealmList; + RealmList get scooters => + RealmObjectBase.get(this, 'scooters') as RealmList; @override - set owner(covariant RealmList value) => + set scooters(covariant RealmList value) => throw RealmUnsupportedSetError(); @override @@ -298,7 +298,7 @@ class ScooterShop extends _ScooterShop ObjectType.realmObject, ScooterShop, 'ScooterShop', [ SchemaProperty('id', RealmPropertyType.objectid, primaryKey: true), SchemaProperty('name', RealmPropertyType.string), - SchemaProperty('owner', RealmPropertyType.object, + SchemaProperty('scooters', RealmPropertyType.object, linkTarget: 'Scooter', collectionType: RealmCollectionType.list), ]); } diff --git a/source/examples/generated/flutter/backlinks_test.snippet.filter-backlinks-rql.dart b/source/examples/generated/flutter/backlinks_test.snippet.filter-backlinks-rql.dart index e4424cd698f..b4216930ff9 100644 --- a/source/examples/generated/flutter/backlinks_test.snippet.filter-backlinks-rql.dart +++ b/source/examples/generated/flutter/backlinks_test.snippet.filter-backlinks-rql.dart @@ -1,6 +1,7 @@ -// Filter tasks through the User's backlink property +// Filter Tasks through the User's backlink property // using `@links..` syntax final jarjarsIncompleteTasks = realm.query( "ALL @links.User.tasks.username == 'jarjar_binks' AND isComplete == false"); -final tasksForHan = realm.query("ALL @links.User.tasks.username == 'han'"); +final tasksForHan = + realm.query("ALL @links.User.tasks.username == 'han'"); diff --git a/source/examples/generated/flutter/backlinks_test.snippet.query-backlink-inverse-relationship.dart b/source/examples/generated/flutter/backlinks_test.snippet.query-backlink-inverse-relationship.dart new file mode 100644 index 00000000000..dde4e068ca7 --- /dev/null +++ b/source/examples/generated/flutter/backlinks_test.snippet.query-backlink-inverse-relationship.dart @@ -0,0 +1,10 @@ +// Tasks have an inverse relationship to Users +final inCompleteTasks = realm.query("isComplete == false"); + +// Find all Users who have an incomplete Task +for (final task in inCompleteTasks) { + final ownersWithIncompleteTasks = task.getBacklinks('tasks'); + for (final user in ownersWithIncompleteTasks) { + print("User ${user.username} has incomplete tasks."); + } +} diff --git a/source/examples/generated/flutter/backlinks_test.snippet.query-backlinks.dart b/source/examples/generated/flutter/backlinks_test.snippet.query-backlink-to-one-relationship.dart similarity index 54% rename from source/examples/generated/flutter/backlinks_test.snippet.query-backlinks.dart rename to source/examples/generated/flutter/backlinks_test.snippet.query-backlink-to-one-relationship.dart index 8fc14f9092e..cbd9b4332cd 100644 --- a/source/examples/generated/flutter/backlinks_test.snippet.query-backlinks.dart +++ b/source/examples/generated/flutter/backlinks_test.snippet.query-backlink-to-one-relationship.dart @@ -1,4 +1,5 @@ +// Persons have a to-one relationship with Bikes final person = realm.query("firstName == 'Anakin'").first; -// Find all bikes that have an owner named Anakin +// Find all Bikes that have an Owner named 'Anakin' final allBikes = person.getBacklinks('owner'); diff --git a/source/examples/generated/flutter/backlinks_test.snippet.query-backlinks-to-many-relationship.dart b/source/examples/generated/flutter/backlinks_test.snippet.query-backlinks-to-many-relationship.dart new file mode 100644 index 00000000000..013e144768e --- /dev/null +++ b/source/examples/generated/flutter/backlinks_test.snippet.query-backlinks-to-many-relationship.dart @@ -0,0 +1,6 @@ +// Scooters have a to-many relationship with ScooterShops +final scooters = realm.query("name == 'Scooterbug'").first; + +// Find all ScooterShops that sell the Scooterbug +final shops = scooters.getBacklinks('scooters'); + diff --git a/source/examples/generated/flutter/schemas.snippet.many-to-many-models.dart b/source/examples/generated/flutter/schemas.snippet.many-to-many-models.dart index 72036ce08f3..008b675f605 100644 --- a/source/examples/generated/flutter/schemas.snippet.many-to-many-models.dart +++ b/source/examples/generated/flutter/schemas.snippet.many-to-many-models.dart @@ -13,5 +13,5 @@ class _ScooterShop { late ObjectId id; late String name; - late List<_Scooter> owner; + late List<_Scooter> scooters; } diff --git a/source/sdk/flutter/crud/read.txt b/source/sdk/flutter/crud/read.txt index 90e72968aad..60068790448 100644 --- a/source/sdk/flutter/crud/read.txt +++ b/source/sdk/flutter/crud/read.txt @@ -152,21 +152,21 @@ Retrieve a collection of all objects of a data model in the database with the .. _flutter-get-backlinks: -Query Linked Objects -~~~~~~~~~~~~~~~~~~~~ +Query Related Objects +~~~~~~~~~~~~~~~~~~~~~ .. versionadded:: 1.9.0 -You can find all objects with an inverse relationship to a given object by calling the -object's :flutter-sdk:`getBacklinks() ` method. +If your data model includes objects that reference other objects, you can query the :ref:`relationship ` using the :flutter-sdk:`getBacklinks() ` method. -In this example, we have a ``Bike`` object model with an ``owner`` property of type ``Person``: +This method returns a :flutter-sdk:`results collection ` of all objects that link to the given object through a to-one, to-many, or inverse relationship. + +In this example, we have a ``Bike`` object model with a to-one relationship defined through an ``owner`` property of type ``Person``: .. literalinclude:: /examples/generated/flutter/schemas.snippet.many-to-one-models.dart :language: dart -We can use the ``getBacklinks()`` method to find any linked objects. This -method returns a :flutter-sdk:`results collection ` of ``Bike`` +We can use the ``getBacklinks()`` method to find any ``Bike`` objects that link to the specified person: .. literalinclude:: /examples/generated/flutter/backlinks_test.snippet.query-backlinks.dart diff --git a/source/sdk/flutter/realm-database/model-data/relationships.txt b/source/sdk/flutter/realm-database/model-data/relationships.txt index 64f2cee6b7b..c94b10dfb68 100644 --- a/source/sdk/flutter/realm-database/model-data/relationships.txt +++ b/source/sdk/flutter/realm-database/model-data/relationships.txt @@ -22,6 +22,11 @@ Embedded objects are similar to relationships, but provide additional constraint For more information about these constraints and how to create embedded objects, refer to the :ref:`Embedded Objects data type documentation `. +.. tip:: Querying Related Objects + + In Flutter v1.9.0 and later, you can use the :flutter-sdk:`getBacklinks() ` method to find objects that link to another object through a relationship. + For more information, refer to :ref:`flutter-get-backlinks`. + .. _flutter-many-to-one-relationship: To-One Relationship