3

我是 MongoDB 以及 MongoDB Realm Sync 的新手。我正在关注Realm Sync 教程Realm 数据模型文档,但我想了解更多信息,因此我调整了 Atlas 集合结构,如下所示。

Projects > Tasks // i.e. tasks is a sub-collection in each project.

我不知道如何提出可以支持 Atlas 子集合的 Realm Sync Schema。我想出的最好的是一个模式,其中Tasks 被建模为Project. 但是,我担心对于有很多任务的项目来说,这可能会达到 16MB(虽然很多!)的文档限制。

{
  "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"
}

期待如何以正确的方式对子集合进行建模。

编辑

这是我的客户端领域模型。

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"
}

就 CRUD 操作而言,我只创建一个新项目并读取现有项目如下。

// Read projects
realm.objects(Project.self).forEach { (project) in
   // Access fields     
}
        
// Create a new project
try! realm.write {
    realm.add(project)
}
4

1 回答 1

2

您的代码看起来很棒,并且您朝着正确的方向前进,因此这个答案是关于建模的更多解释和建议,而不是硬代码。

首先,Realm 对象是延迟加载的,这意味着它们仅在使用时才加载。数以万计的对象对设备内存的影响很小。因此,假设您有 10,000 个用户,并且您“全部加载”

let myTenThousandUsers = realm.objects(UserClass.self)

嗯,没什么大不了的。然而,这样做

let someFilteredUsers = myTenThousandUsers.filter { $0.blah == "blah" }

将(可能)产生一个问题 - 如果返回 10,000 个用户,他们都被加载到内存中,可能会压倒设备。这是一个 Swift 函数,通常应该避免使用 Swift“转换”Realms 惰性数据(取决于用例)

使用 Swift .forEach 观察这段代码

realm.objects(Project.self).forEach { (project) in
   // Access fields     
}

可能会导致问题,具体取决于对这些项目对象所做的事情 - 如果它们很多,将它们用作 tableView 数据源可能会很麻烦。

第二件事是关于每个文档 16Mb 限制的问题。为了清楚起见,Atlas 文件是这样的

{
   field1: value1,
   field2: value2,
   field3: value3,
   ...
   fieldN: valueN
}

其中 value 可以是任何 BSON 数据类型,例如其他文档、数组和文档数组。

在您的结构中,var tasks = RealmSwift.List<Task>()其中 Task 是一个嵌入的对象。虽然概念上嵌入的对象是对象,但我相信它们计入单个文档限制,因为它们是嵌入的(如果我错了,请纠正我);随着它们数量的增加,随附文档的大小也会增加 - 请记住,16Mb 的文本是一个巨大的文本,因此这将/可能等同于每个项目的数百万个任务。

简单的解决方案是不嵌入它们并让它们独立存在。

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"
    }
}

然后每个可以是 16Mb,并且可以将“无限数量”与单个项目相关联。嵌入对象的一个​​优点是一种级联删除,当父对象被删除时,子对象也会被删除,但是从项目到任务是一对多的关系——删除一堆属于父对象的任务很容易。

哦 - 不使用嵌入对象的另一种情况 - 特别是对于这个用例 - 它们不能具有索引属性。索引可以大大加快一些查询。

于 2021-03-15T18:50:59.047 回答