Soy nuevo en MongoDB y en MongoDB Realm Sync. Estaba siguiendo el tutorial de Realm Sync y los documentos del modelo de datos de Realm , pero quería aprender más, así que ajusté la estructura de la colección Atlas de la siguiente manera.
Projects > Tasks // ie tasks is a sub-collection in each project. Lo que no sé es cómo llegar a Realm Sync Schema que pueda admitir subcolecciones de Atlas. Lo mejor que se me ocurrió es un Esquema en el que las Task se modelan como una matriz dentro del Project . Pero me preocupa que esto pueda alcanzar el límite de documentos de 16 MB (¡aunque mucho!) para proyectos con muchas tareas.
{ "bsonType": "object", "properties": { "_id": { "bsonType": "objectId" }, "_partition": { "bsonType": "string" }, "name": { "bsonType": "string" }, "tasks": { "bsonType": "array", "items": { "bsonType": "object", "title": "Task", "properties": { "name": { "bsonType": "string" }, "status": { "bsonType": "string" } } } } }, "required": [ "_id", "_partition", "name", ], "title": "Project" }Mirando hacia adelante sobre cómo modelar la subcolección de la manera correcta.
Editar
Aquí están mis modelos Realm del lado del cliente.
import Foundation import RealmSwift class Project: Object { @objc dynamic var _id: String = ObjectId.generate().stringValue @objc dynamic var _partition: String = "" // user.id @objc dynamic var name: String = "" var tasks = RealmSwift.List<Task>() override static func primaryKey() -> String? { return "_id" } } class Task: EmbeddedObject { @objc dynamic var name: String = "" @objc dynamic var status: String = "Pending" }En lo que respecta a las operaciones CRUD, solo creo un nuevo proyecto y leo los proyectos existentes de la siguiente manera.
// Read projects realm.objects(Project.self).forEach { (project) in // Access fields } // Create a new project try! realm.write { realm.add(project) }Su código se ve muy bien y se dirige en la dirección correcta, por lo que esta respuesta es más una explicación y sugerencias sobre el modelado que el código duro.
En primer lugar, los objetos Realm se cargan de forma diferida, lo que significa que solo se cargan cuando se usan. Decenas de miles de objetos tendrán muy poco impacto en la memoria de un dispositivo. Suponga que tiene 10 000 usuarios y los 'carga todos'
let myTenThousandUsers = realm.objects(UserClass.self)meh, no es gran cosa. Sin embargo, haciendo esto
let someFilteredUsers = myTenThousandUsers.filter { $0.blah == "blah" }creará (podría) crear un problema: si eso devuelve 10,000 usuarios , todos estarán cargados en la memoria, posiblemente abrumando el dispositivo. Esa es una función de Swift y, en general, se debe evitar la 'conversión' de datos perezosos de Realms usando Swift (depende del caso de uso)
La observación de este código usando Swift .forEach
realm.objects(Project.self).forEach { (project) in // Access fields }podría causar problemas dependiendo de lo que se haga con esos objetos del proyecto; usarlos como fuente de datos de tableView podría ser problemático si hay muchos de ellos.
Lo segundo es la pregunta sobre el límite de 16 Mb por documento. Para mayor claridad, un documento de Atlas es este
{ field1: value1, field2: value2, field3: value3, ... fieldN: valueN }donde el valor puede ser cualquiera de los tipos de datos BSON, como otros documentos, matrices y matrices de documentos.
En su estructura, var tasks = RealmSwift.List<Task>() donde Task es un objeto incrustado . Si bien los objetos incrustados conceptualmente son objetos, creo que cuentan para el límite de un solo documento porque están incrustados (corríjame si me equivoco); a medida que crece el número de ellos, crece el tamaño del documento adjunto, teniendo en cuenta que 16 Mb de texto es ENORME, por lo que equivaldría a millones de tareas por proyecto.
La solución simple es no incrustarlos y hacer que se mantengan solos.
class Task: Object { @objc dynamic var _id: String = ObjectId.generate().stringValue @objc dynamic var _partition: String = "" @objc dynamic var name: String = "" @objc dynamic var status: String = "Pending" override static func primaryKey() -> String? { return "_id" } }Entonces, cada uno puede tener 16 Mb y un 'número ilimitado' puede asociarse con un solo proyecto. Una ventaja de los objetos incrustados es un tipo de eliminación en cascada en la que cuando se elimina el objeto principal, los objetos secundarios también lo hacen, pero con una relación 1-muchos desde Proyecto a Tareas: eliminar un montón de tareas que pertenecen a un elemento principal es fácil.
Oh, otro caso para no usar objetos incrustados, especialmente para este caso de uso, es que no pueden tener propiedades indexadas. La indexación puede acelerar en gran medida algunas consultas.