重新设计基本 API
因为从最初编写 Mabolo 以来,我对 MongoDB 的了解又深入了许多,同时 Mabolo 也切换到了 MongoDB Driver 2.x for Node.js, 需要对基本 API 做一些修改(不包括嵌入式文档)。
原 AbstractModel 将被拆分成 MaboloCollection 和 MaboloDocument, 分别包含静态方法和实例方法。
Mabolo
这部分几乎没什么变化,不过 schema 改成了通过 Joi Schema 来定义。
.ObjectId.model(name, joiSchema, options?) -> Model#constructor(mongodbUrl)#connect(mongodbUrl)#model(name, joiSchema, options?) -> Model#bind(Model)
MaboloCollection
在 MongoDB Driver 2.x for Node.js 里,这部分的 API 变化了一些,主要是将原来的 update 等函数分为了 updateOne, updateMany 这类的函数。
在 Mabolo 中,因为除了 Collection 还有 Document 这个抽象层级,所以 update 和 remove 默认是更新或删除多个文档,除非你使用 findFirstAndUpdate 或 findFirstAndRemove;原来的 findOne 改成了更具体的 findFirst;同时 ensureIndex 这类管理 Collection 的 API 被移除了,因为按照我最近一段时间的经验,允许代码去创建数据库索引并不是一个好主意(而是应该使用专门的 Migrate 工具)。
.create(object) -> Promise(Document).find(query) -> Cursor.count(query, options?) -> Promise(Number).findFirst(query, options?) -> Promise(Document?).findById(id, options?) -> Promise(Document?).aggregate(commands, options?) -> Cursor.update(query, updates, options?) -> Promise.findFirstAndUpdate(query, updates, options?) -> Promise(Document?).findByIdAndUpdate(id, updates, options?) -> Promise(Document?).remove(query, options?) -> Promise.findFirstAndRemove(query, options?) -> Promise(Document?).findByIdAndRemove(id, options?) -> Promise(Document?)
MaboloDocument
新增了 updateIf 和 removeIf 来支持在更新或删除文档时附加查询条件;新增 fetch 和 refresh 分别用来自动重新抓取数据和从用户指定的对象更新数据;原 modify 方法更名为更具体的 transaction,考虑到之前版本的 save 过于鸡肋(不能保存已存在于数据库中的文档),决定将 save 实现为一个「一次性事务」,即只尝试保存一次,若失败(文档被并发修改)则抛异常。
#constructor(object)#save() -> Promise#validate() -> Promise#update(updates, options?) -> Promise#updateIf(query, updates, options?) -> Promise#remove() -> Promise#removeIf(query, options?) -> Promise#transaction(transaction) -> Promise#fetch() -> Promise#refresh(latest)#toObject()
updateIf 和 remoteIf 改为 updateWithQuery 和 removeWithQuery 在命名上可能会更恰当一些。
按照官方的 API, .find() 会返回一个 Cursor 实例,设置排序、结果行数都需要在 Cursor 实例上进行操作。为了让 Mabolo 保持简单且与 MongoDB API 一致,应该让 .find(query) 也返回 Cursor, 但需要在返回的 Cursor 实例上设置 transform, 将返回的文档转换为 Mabolo 的文档对象。
需要做同样处理的还有 .aggregate()。