node.js - 使用 Mongoose : How to synchronize changes 进行非规范化

标签 node.js mongodb mongoose denormalization

当您拥有非规范化架构时,传播更新的最佳方式是什么?是否应该全部在同一个函数中完成?

我有这样的架构:

var Authors = new Schema({
    ...
    name: {type: String, required:true},
    period: {type: Schema.Types.ObjectId, ref:'Periods'},
    quotes: [{type: Schema.Types.ObjectId, ref: 'Quotes'}]
    active: Boolean,
    ...
})

然后:

var Periods = new Schema({
    ...
    name: {type: String, required:true},
    authors: [{type: Schema.Types.ObjectId, ref:'Authors'}],
    active: Boolean,
    ...
})

现在说我想对作者进行非规范化,因为 period 字段将始终只使用句点的名称(这是唯一的,不能有两个同名的句点)。然后说我把我的模式变成了这样:

var Authors = new Schema({
        ...
        name: {type: String, required:true},
        period: String, //no longer a ref
        active: Boolean,
    ...
})

现在 Mongoose 不再知道 period 字段已连接到 Period 架构。因此,当一个时期的名称发生变化时,由我来更新该字段。我创建了一个提供如下接口(interface)的服务模块:

exports.updatePeriod = function(id, changes) {...}

在此功能中,我通过更改来更新需要更新的期间文档。所以这是我的问题。那么,我应该更新此方法中的所有作者吗?因为那时该方法必须了解 Author 模式和任何其他使用句点的模式,从而在这些实体之间创建大量耦合。有没有更好的办法?

也许我可以发出一个周期已更新的事件,并且所有具有非规范化周期引用的模式都可以观察到它,这是一个更好的解决方案吗?我不太确定如何解决这个问题。

最佳答案

好的,虽然我在等待比我自己更好的答案,但我会尝试发布我到目前为止所做的事情。

前置/后置中间件

我尝试的第一件事是使用 pre/post middlewares同步相互引用的文档。 (例如,如果您有 AuthorQuote,并且 Author 有一个类型为的数组:quotes: [{type: Schema.Types.ObjectId, ref:'Quotes'}],那么每当一个 Quote 被删除时,你必须从数组中删除它的 _id。或者如果 Author 被删除,你可能想要他的所有引号已删除)。

这种方法有一个重要的优势:如果您在其自己的文件中定义每个 Schema,您可以在其中定义中间件并将其整齐地组织。每当您查看架构时,您都可以在下方看到它的作用、其更改如何影响其他实体等:

var Quote = new Schema({
    //fields in schema
})
//its quite clear what happens when you remove an entity
Quote.pre('remove', function(next) {
    Author.update(
        //remove quote from Author quotes array.
    )
})

The main disadvantage however is that these hooks are not executed when you call update or any Model static updating/removing functions .相反,您需要检索文档,然后对它们调用 save()remove()

另一个较小的缺点是 Quote 现在需要知道引用它的任何人,以便在更新或删除 Quote 时更新它们。因此,假设 Period 有一个引号列表,而 Author 也有一个引号列表, Quote 需要知道这两个来更新它们。

原因是这些函数直接向数据库发送原子查询。虽然这很好,但我讨厌使用 save()Model.Update(...) 之间的不一致。也许将来别人或你不小心使用了静态更新功能,而你的中间件没有被触发,给你带来了难以摆脱的头痛。

NodeJS 事件机制

我目前所做的并不是最理想的,但它为我提供了足够的好处,实际上超过了缺点(或者我相信,如果有人愿意给我一些反馈,那就太好了)。我创建了一个围绕模型的服务,例如 AuthorService 扩展 events.EventEmitter 并且是一个构造函数,大致如下所示:

function AuthorService() {
    var self = this

    this.create = function() {...}
    this.update = function() {
        ...
        self.emit('AuthorUpdated, before, after)
        ...
    }
}

util.inherits(AuthorService, events.EventEmitter)
module.exports = new AuthorService()

优点:

  • 任何感兴趣的功能都可以注册到服务中 事件并得到通知。这样,例如,当 Quote 是 更新,AuthorService 可以监听它并更新 Authors 因此。 (注1)
  • Quote 不需要知道引用它的所有文档,Service 只需触发 QuoteUpdated 事件,发生这种情况时需要执行操作的所有文档都会这样做。

注意 1:只要有人需要与 Mongoose 交互时使用此服务。

缺点:

  • 添加了样板代码,直接使用服务而不是 Mongoose 。
  • 现在,当您调用什么函数时,我们并不十分清楚 触发事件。
  • 您以易读性为代价将生产者和消费者分离(因为 你只是emit('EventName', args),这不是很明显 哪些服务正在监听此事件)

另一个缺点是有人可以从服务中检索模型并调用 save(),其中事件不会被触发,但我确信这一点可以通过这两种解决方案之间的某种混合来解决。

我对这个领域的建议非常开放(这就是我首先发布这个问题的原因)。

关于node.js - 使用 Mongoose : How to synchronize changes 进行非规范化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22201940/

相关文章:

java - 使用 Spring Data 在 MongoDB 中求和聚合

node.js - Mongoose 计数文档

node.js - 聚合返回空数组 - Mongoose

node.js - Mongoose 不创建索引

AngularJs 图片上传到 S3

node.js - 如何编写基于 Node.js 的 cron 作业来删除 MongoDB 集合并发出 db.copyDatabase 命令

node.js - 如何强制 Angular 在 HTML5 模式下向服务器发送请求?

javascript - 测试中的 NestJS 全局模块

javascript - MongoError : Unknown modifier: $pushAll in node js

ruby-on-rails - 使用 Mongoid 进行不区分大小写的排序