El SDK de Flutter admite tipos de datos del lenguaje Dart, un subconjunto limitado de BSONtipos y UUID.
Para aprender cómo se asignan tipos de datos específicos a los BSON types en un esquema de App Services, consulta Mapeo del modelo de datos en la documentación de Atlas App Services.
Dart Types
Realm supports the following Dart types:
intdoubleboolStringDateTime
Fecha y hora
When you use DateTime with the Realm Flutter SDK, you can declare it in the model as you would any other Dart type:
() class _Vehicle { () late ObjectId id; late String nickname; late DateTime dateLastServiced; }
However, it is important to note that Realm stores DateTime in UTC. When you use DateTime, you must create it in UTC or convert it with .toUtc() before you store it. If your application requires it, you can convert it back to local or the desired time zone when reading from Realm.
// Create a Realm object with date in UTC, or convert with .toUtc() before storing final subaruOutback = realm.write<Vehicle>(() { return realm.add( Vehicle(ObjectId(), 'Subie', DateTime.utc(2022, 9, 18, 12, 30, 0))); }); final fordFusion = Vehicle(ObjectId(), 'Fuse', DateTime(2022, 9, 18, 8, 30, 0).toUtc()); realm.write(() { realm.add(fordFusion); }); // When you query the object, the `DateTime` returned is UTC final queriedSubaruOutback = realm.all<Vehicle>().query('nickname == "Subie"')[0]; // If your app needs it, convert it to Local() or the desired time zone final localizedSubieDateLastServiced = queriedSubaruOutback.dateLastServiced.toLocal();
Objetos de referencia de Realm
You can also reference one or more Realm objects from another. Learn more in the relationship properties documentation.
Colecciones
Una colección de Realm contiene cero o más instancias de un tipo de dato compatible con Realm. En una colección de Realm, todos los objetos están en la colección son del mismo tipo.
You can filter and sort any collection using Realm's query language. Collections are live objects, so they always reflect the current state of the realm instance. The contents of a collection update when new elements are added to or deleted from the collection or from its Realm.
También puede escuchar cambios en la colección suscribiéndose a notificaciones de cambio.
Realm tiene los siguientes tipos de colecciones:
RealmList
Realm objects can contain lists of any supported data type. Realm uses the RealmList data type to store the data.
Cuando incluyes RealmObjects como los ítems en un RealmList, representa una relación de muchos.
Deleting an object from the database will remove it from any RealmLists where it existed. Therefore, a RealmList of RealmObject types will never contain null values. Also, a RealmList can contain multiple references to the same RealmObject.
A RealmList of primitive types can contain null values. If you do not want to allow null values in a list, then either use non-nullable types in the list declaration (for example, use List<int> instead of List<int?>).
A RealmList is mutable and you can add and remove elements on a RealmList within a write transaction.
Add a RealmList to a Schema
Puede agregar un RealmList a su esquema de objeto Realm definiendo una propiedad como tipo List<T> donde T puede ser cualquier tipo de datos Realm compatible (excepto otras colecciones), en su modelo de objeto Realm.
() class _Player { () late ObjectId id; late String username; // `inventory` property of type RealmList<Item> // where Items are other RealmObjects late List<_Item> inventory; // `traits` property of type RealmList<String> // where traits are Dart Strings. late List<String> traits; } () class _Item { () late ObjectId id; late String name; late String description; }
Trabajar con una RealmList
Cambiado en la versión 2.0.0: Obtén RealmList por nombre de propiedad con dynamic.getList()
El siguiente ejemplo demuestra algunos usos básicos de RealmList. Para obtener más información sobre todos los métodos disponibles, consulta la documentación de Referencia de RealmList.
final artemis = realm.write(() => realm.add(Player(ObjectId(), 'Art3mis', inventory: [ Item(ObjectId(), 'elvish sword', 'sword forged by elves'), Item(ObjectId(), 'body armor', 'protects player from damage'), ], traits: [ 'brave', 'kind' ]))); // Get a RealmList by property name with dynamic.getList() final inventory = artemis.dynamic.getList('inventory'); // Use RealmList methods to filter results RealmList<String> traits = artemis.traits; final brave = traits.firstWhere((element) => element == 'brave'); final elvishSword = artemis.inventory.where((item) => item.name == 'elvish sword').first; // Query RealmList with Realm Query Language final playersWithBodyArmor = realm.query<Player>("inventory.name == \$0", ['body armor']); print("LEN ${playersWithBodyArmor.length}");
RealmSet
Realm objects can contain sets of any supported data type except another collection. Realm uses the RealmSet data type to store the data. In a RealmSet collection, all values are unique. RealmSet extends the native Dart Set data type with additional Realm-specific properties and methods.
Cuando incluyes RealmObjects como los ítems en un RealmSet, representa una relación de muchos.
A RealmSet is mutable and you can add and remove elements in a RealmSet within a write transaction.
Add a RealmSet to a Schema
You can add a RealmSet to your Realm Object schema by defining a property as type Set<T> where T can be any supported Realm data type except other collections, in your Realm Object model.
When defining a RealmSet in a schema:
A set of primitive types can be defined as either nullable or non-nullable. For example, both
Set<int>andSet<int?>are valid in a Realm schema.A set of
RealmObjectandRealmValuetypes can only be non-nullable. For exampleSet<RealmValue>is valid, butSet<RealmValue?>is not valid.Usted no puede definir valores por defecto al definir un grupo en un esquema. Por ejemplo,
Set mySet = {0,1,2}no es válido.
() class _RealmSetExample { late Set<String> primitiveSet; late Set<int?> nullablePrimitiveSet; late Set<_SomeRealmModel> realmObjectSet; } () class _SomeRealmModel { late ObjectId id; }
Trabajar con un RealmSet
Cambiado en la versión 2.0.0: Obtén RealmSet por nombre de propiedad con dynamic.getSet()
The following example demonstrates some basic usage of RealmSet. For more information about all available methods, refer to the RealmSet reference documentation.
final realm = Realm( Configuration.local([RealmSetExample.schema, SomeRealmModel.schema])); // Pass native Dart Sets to the object to create RealmSets final setExample = RealmSetExample( primitiveSet: {'apple', 'pear'}, nullablePrimitiveSet: {null, 2, 3}, realmObjectSet: {SomeRealmModel(ObjectId())}); // Add RealmObject to database realm.write(() => realm.add(setExample)); // Once you add the sets, they are of type RealmSet RealmSet primitiveSet = setExample.primitiveSet; // Modify RealmSets of RealmObjects in write transactions realm.write(() { // Add element to a RealmSet with RealmSet.add() setExample.realmObjectSet.add(SomeRealmModel(ObjectId())); // Remove element from a RealmSet with RealmSet.remove() setExample.primitiveSet.remove('pear'); }); // Check if a RealmSet contains an element with RealmSet.contains() if (setExample.primitiveSet.contains('apple')) { print('Set contains an apple'); } // Get RealmSet by property name with dynamic.getSet() final getSetResult = setExample.dynamic.getSet('primitiveSet'); // Check number of elements in a RealmSet with RealmSet.length print( 'Set now has ${getSetResult.length} elements'); // Prints 'Set now has 1 elements' // Query RealmSets using Realm Query Language final results = realm.query<RealmSetExample>('\$0 IN nullablePrimitiveSet', [null]);
RealmMap
Novedad en la versión 1.7.0.
RealmMap is a collection that contains key-value pairs of <String, T>, where T is any data type supported by the SDK. Map keys may not contain . or start with $ unless you use percent-encoding.
A RealmMap is mutable and you can add and remove elements in a RealmMap within a write transaction. You can listen for RealmMap entry changes using a change listener.
Agrega un RealmMap a un esquema
Puede agregar un RealmMap a su esquema de objeto Realm definiendo una propiedad como tipo RealmMap<String, T> donde T puede ser cualquier tipo de datos Realm compatible (excepto otras colecciones), en su modelo de objeto Realm.
() class _MapExample { late Map<String, int> map; late Map<String, int?> nullableMap; }
Work with a RealmMap
Changed in version 2.0.0: Get RealmMap by property name with dynamic.getMap()
The following example demonstrates some basic usage of RealmMap. For more information about all available methods, refer to the RealmMap reference documentation.
final realm = Realm(Configuration.local([MapExample.schema])); // Pass native Dart Maps to the object to create RealmMaps final mapExample = MapExample( map: { 'first': 1, 'second': 2, 'third': 3, }, nullableMap: { 'first': null, 'second': 2, 'third': null, }, ); // Add RealmObject to the database realm.write(() => realm.add(mapExample)); // Once you add maps, they are of type RealmMap RealmMap map = mapExample.map; // Modify RealmMaps in write transactions realm.write(() { // Update value by key with .update() or [value] = newValue mapExample.nullableMap['second'] = null; mapExample.map.update('first', (value) => 5); mapExample.nullableMap.update('fourth', (v) => 4, ifAbsent: () => null); // Add a new map entry with .addEntries() const newMap = {'fourth': 4}; mapExample.map.addEntries(newMap.entries); }); // Check a RealmMap with .containsKey() or .containsValue() if (mapExample.map.containsKey('first')) { print('Map contains key "first"'); } else if (mapExample.map.containsValue(null)) { print('Map contains null value'); } else { print('These aren\'t the maps you\'re looking for'); } // Get a RealmMap by property name with dynamic.getMap() final getPrimitiveMap = mapExample.dynamic.getMap('map'); // Check the number of elements in a RealmMap with RealmMap.length print( 'Map contains ${getPrimitiveMap.length} elements'); // Prints 'Map contains 4 elements' // Query RealmMaps using Realm Query Language final results = realm.query<MapExample>('map.first == \$0', [5]);
RealmResults
Una colección RealmResults representa los resultados de evaluación perezosa de una operación de query. A diferencia de un(a) RealmList, los resultados son inmutables: no puedes agregar ni remover elementos en la colección de resultados. Esto se debe a que el contenido de una colección de resultados está determinado por una query a la base de datos.
Realm.all() y Realm.query() devolver RealmResults. Para obtener más información sobre las consultas en Realm, consulte Operaciones de lectura.
RealmResults<Player> players = realm.all<Player>(); RealmResults<Player> bravePlayers = realm.query<Player>('ANY traits == \$0', ['brave']);
Results are Lazily Evaluated
Realm solo ejecutar una consulta cuando realmente se hace una solicitud de los resultados de esa query, por ejemplo, al acceder a elementos de la colección de resultados. Esta evaluación perezosa te permite escribir código elegante y de alto rendimiento para manejar grandes conjuntos de datos y queries complejas.
Las colecciones están en tiempo real
Like live objects, Realm collections are usually live:
Las colecciones de resultados en vivo siempre reflejan los resultados actuales de la consulta asociada.
Listas en vivo de
RealmObjectssiempre reflejan el estado actual de la relación en la instancia de Realm.
There are two cases, however, when a collection is not live:
The collection is unmanaged: a
RealmListproperty of a Realm object that has not been added to a realm yet or that has been copied from a realm.The collection is frozen.
Combinado con escuchar cambios en una colección, las colecciones en tiempo real permiten un código limpio y reactivo. Por ejemplo, supongamos que tu vista muestra los resultados de una query. Puedes mantener una referencia a la colección de resultados en tu clase de vista y luego leer la colección de resultados según sea necesario, sin tener que actualizarla o validar que esté al día.
Importante
Indexes may change
Dado que los resultados se actualizan automáticamente, no se debe almacenar el índice posicional de un objeto en la colección ni la cuenta de objetos en una colección. El índice almacenado o el valor de la cuenta podría estar desactualizado para cuando lo utilices.
Tipos de datos adicionales compatibles
ObjectId
ObjectId is a MongoDB-specific 12-byte unique value which you can use as an identifier for objects. ObjectId is indexable and can be used as a primary key.
To define a property as an ObjectId, set its type as ObjectId in your object model.
() class _ObjectIdPrimaryKey { () late ObjectId id; }
Call ObjectId() to set any unique identifier properties of your object. Alternatively, pass a string to ObjectId() to set the unique identifier property to a specific value.
final id = ObjectId(); final object = ObjectIdPrimaryKey(id);
UUID
UUID (Universal Unique Identifier) is a 16-byte unique value. You can use a UUID as an identifier for objects. UUIDs are indexable and you can use them as primary keys.
Nota
Uso de UUID en lugar de ObjectId
In general, you can use UUID for any fields that function as a unique identifier. Using UUID might be particularly useful if you are migrating data not stored in MongoDB since it is likely that your object's unique identifiers are already of a UUID type. Alternatively, using ObjectId might be useful for a collection of data that already exists in MongoDB.
To define a property as a UUID, set its type as Uuid in your object model.
() class _UuidPrimaryKey { () late Uuid id; }
Para establecer cualquier propiedad de identificador único de su objeto a un valor aleatorio, llame a uno de los métodos Uuid para crear un UUID, como Uuid.v4().
final myId = Uuid.v4(); final object = UuidPrimaryKey(myId);
Decimal128
Dart doesn't have a native decimal type. You can use Decimal128, which is a 128-bit implementation of IEEE-754. When defining a decimal type, use the Decimal128 BSON type.
When using Decimal128, be aware that the Dart compareTo() method implements total ordering that mimics the Dart double type. This means the following things are true when using compareTo():
All
NaNvalues are considered equal and greater than any numeric value.-Decimal128.zerois less thanDecimal128.zero(and the integer 0) but greater than any non-zero negative value.Negative infinity is less than all other values and positive infinity is greater than all non-NaN values.
All other values are compared using their numeric value.
RealmValue
Importante
Cambios en RealmValue en Flutter SDK v2.0.0
La versión del SDK de Flutter actualiza 2.0.0 RealmValue para permitir un List Map tipo o RealmValue de, lo que ofrece mayor flexibilidad al modelar datos no estructurados. Consulte Modelar datos no estructurados para obtener más información.
Esta actualización también incluye los siguientes cambios importantes, que pueden afectar a tu aplicación al actualizar a la versión v2.0.0 o posterior:
RealmValue.typeis now an enum ofRealmValueTypeinstead ofType.RealmValue.uint8Listse renombra aRealmValue.binary.
For more information on how to upgrade an existing app from an earlier version to v2.0.0 or later, refer to Upgrade to Flutter SDK v2.0.0.
The RealmValue data type is a mixed data type that can represent any other valid data type except embedded objects. In Flutter SDK v2.0.0 and later, RealmValue can represent a List<RealmValue> or Map<String, RealmValue>.
Definir una propiedad RealmValue
Para definir una propiedad RealmValue, establece su tipo en el modelo de objeto. RealmValue es indexable, pero no puede ser llave primaria. También puedes definir las propiedades como colecciones (listas, sets o mapas) de tipo RealmValue.
() class _RealmValueExample { () late RealmValue singleAnyValue; late List<RealmValue> listOfMixedAnyValues; late Set<RealmValue> setOfMixedAnyValues; late Map<String, RealmValue> mapOfMixedAnyValues; }
Nota
RealmValue no es nulo pero puede contener valores nulos
Al definir su esquema de objeto de Realm, no puede crear un RealmValue anulable. Sin embargo, si deseas que una propiedad RealmValue contenga un valor nulo, puedes usar la propiedad especial RealmValue.nullValue().
Create a RealmValue
To add a RealmValue to a Realm object, call RealmValue.from() on the data or RealmValue.nullValue() to set a null value.
final realm = Realm(Configuration.local([RealmValueExample.schema])); realm.write(() { // Use 'RealmValue.from()' to set values var anyValue = realm.add(RealmValueExample( // Add a single `RealmValue` value singleAnyValue: RealmValue.from(1), // Add a list of `RealmValue` values listOfMixedAnyValues: [Uuid.v4(), 'abc', 123].map(RealmValue.from), // Add a set of `RealmValue` values setOfMixedAnyValues: { RealmValue.from('abc'), RealmValue.from('def') }, // Add a map of string keys and `RealmValue` values mapOfMixedAnyValues: { '1': RealmValue.from(123), '2': RealmValue.from('abc') })); // Use 'RealmValue.nullValue()' to set null values var anyValueNull = realm.add(RealmValueExample( singleAnyValue: RealmValue.nullValue(), listOfMixedAnyValues: [null, null].map(RealmValue.from), setOfMixedAnyValues: {RealmValue.nullValue()}, mapOfMixedAnyValues: {'null': RealmValue.nullValue()}));
Acceso al tipo de datos RealmValue
Cambiado en la 2.0.0 versión: RealmValueType RealmValue.typeRealmValue.binary RealmValue.uint8Listla enumeración reemplaza a. reemplaza a.
Para acceder a los datos almacenados en un RealmValue, puede utilizar:
RealmValue.value, que devuelve unObject?.RealmValue.as<T>, que obtiene los datos y los convierte al tipo deseado.
for (var obj in data) { for (var mixedValue in obj.listOfMixedAnyValues) { // Use RealmValue.value to access the value final value = mixedValue.value; if (value is int) { sum = sum + value; } else if (value is String) { combinedStrings += value; } // Use RealmValue.as<T> to cast value to a specific type try { final intValue = mixedValue.as<int>(); sum = sum + intValue; } catch (e) { log('Error casting value to int: $e'); } } }
You can check the type of data currently stored in a RealmValue property by accessing the type property. Starting with Flutter SDK v2.0.0, this returns a RealmValueType enum. In earlier SDK versions, the SDK returned a RealmValue.value.runtimeType.
The following example uses RealmValueType to run calculations based on the data type.
final data = realm.all<RealmValueExample>(); for (var obj in data) { final anyValue = obj.singleAnyValue; // Access the RealmValue.type property switch (anyValue.type) { // Work with the returned RealmValueType enums case RealmValueType.int: approximateAge = DateTime.now().year - anyValue.as<int>(); break; case RealmValueType.dateTime: approximateAge = (DateTime.now().difference(anyValue.as<DateTime>()).inDays / 365) .floor(); break; case RealmValueType.string: final birthday = DateTime.parse(anyValue.as<String>()); approximateAge = (DateTime.now().difference(birthday).inDays / 365).floor(); break; // Handle other possible types ... default: log('Unhandled type: ${anyValue.type}'); } }
Collections as Mixed
Changed in version 2.0.0: RealmValue properties can contain lists or maps of mixed data.
In version 2.0.0 and later, a mixed data type can hold collections (a list or map, but not a set) of mixed elements. You can use mixed collections to model unstructured or variable data. For more information, refer to Model Unstructured Data.
Se pueden anidar colecciones mixtas hasta 100 niveles.
You can query mixed collection properties and register a listener for changes, as you would a normal collection.
You can find and update individual mixed collection elements
You cannot store sets or embedded objects in mixed collections.
To use mixed collections, define the mixed type property in your data model. Then, create the list or map collections using RealmValue.from().
realm.write(() { realm.add(RealmValueCollectionExample( // Set the RealmValue as a map of mixed data singleAnyValue: RealmValue.from({ 'int': 1, // You can nest RealmValues in collections 'listOfInt': [2, 3, 4], 'mapOfStrings': {'1': 'first', '2': 'second'}, // You can also nest collections within collections 'mapOfMaps': [ { 'nestedMap_1': {'1': 1, '2': 2}, 'nestedMap_2': {'3': 3, '4': 4} } ], 'listOfMaps': [ { 'nestedList_1': [1, 2, 3], 'nestedList_2': [4, 5, 6] } ] })));
Uint8List
Uint8List es un tipo de dato binario de dart:typed_data. Puedes utilizar este tipo de datos en modelos de objetos y valores de propiedades.
To define a property as Uint8List, you must first import dart:typed_data. Then, set the object's type as Uint8List in your object model.
() class _BinaryExample { late String name; late Uint8List requiredBinaryProperty; late Uint8List? nullableBinaryProperty; }
To add Uint8List to a Realm object, call Uint8List.fromList() on the data.
final realm = Realm(Configuration.local([BinaryExample.schema])); realm.write(() { realm.addAll([ BinaryExample("Example binary object", Uint8List.fromList([1, 2])) ]); });
objeto incrustado
Realm treats each embedded object as nested data inside of a parent object. An embedded object inherits the lifecycle of its parent object. It cannot exist as an independent Realm object. Embedded objects have the following properties:
Embedded objects are deleted when their parent object is deleted or their parent no longer references them.
No se puede reasignar un objeto incrustado a un objeto principal diferente.
you cannot link to an embedded object from multiple parent objects.
Solo puedes query un objeto incrustado accediendo a él a través de su padre.
Declare an embedded objects by passing ObjectType.embeddedObject to the @RealmModel() annotation. Embedded objects must be nullable when defining them in the parent object's RealmModel. You must also include the embedded object's schema in the realm's Configuration.
The following example shows how to model an embedded object in a Realm schema. The _Address model is embedded within the _Person model.
// The generated `Address` class is an embedded object. (ObjectType.embeddedObject) class _Address { late String street; late String city; late String state; late String country; } () class _Person { () late ObjectId id; late String name; // Embedded object in parent object schema late _Address? address; // Must be nullable }
You can use the parent property to access the parent of the embedded object.
The following example shows the unique considerations when working with embedded objects. The example uses the Address embedded object generated from the _Address RealmModel in the above schema.
// Both parent and embedded objects in schema final realm = Realm(Configuration.local([Person.schema, Address.schema])); // Create an embedded object. final joesHome = Address("500 Dean Street", "Brooklyn", "NY", "USA"); final joePrimaryKey = ObjectId(); final joe = Person(joePrimaryKey, "Joe", address: joesHome); realm.write(() => realm.add(joe)); // Update an embedded object property. realm.write(() { joe.address?.street = "800 Park Place"; }); // Query a collection of embedded objects. // You must access the embedded object through the parent RealmObject type. final peopleWithNewYorkHomes = realm.query<Person>("address.state = 'NY'"); // Overwrite an embedded object. // Also deletes original embedded object from realm. final joesNewHome = Address("12 Maple Way", "Toronto", "ON", "Canada"); realm.write(() { joe.address = joesNewHome; }); // You can access the parent object from an embedded object. final thePersonObject = joesNewHome.parent; // Delete embedded object from parent object. realm.write(() => realm.delete(joe.address!)); // Add address back for the following example. final anotherNewHome = Address("202 Coconut Court", "Miami", "FL", "USA"); realm.write(() { joe.address = anotherNewHome; }); // Deleting the parent object also deletes the embedded object. realm.write(() => realm.delete(joe));
Ejemplo
El siguiente modelo incluye algunos tipos de datos admitidos.
part 'car.realm.dart'; // The generated `Address` class is an embedded object. (ObjectType.embeddedObject) class _Address { late String street; late String city; late String state; late String country; } () class _Person { () late ObjectId id; late String name; // Embedded object in parent object schema late _Address? address; // Must be nullable } () class _Car { () late ObjectId id; String? licensePlate; bool isElectric = false; double milesDriven = 0; late List<String> attributes; late _Person? owner; }