同步多个mongoDB并避免重复的_id

时间:2015-12-07 12:22:30

标签: mongodb mongoose

问题

我有一个主寄存器和x个子寄存器,它们将数据流传输到主寄存器。我在夜间使用主寄存器同步这些寄存器。因此,白天将在x1,x2,...xn中创建数据,并在晚上将所有数据发送到主寄存器。

这不是很可能,但可能是例如x1x2生成相同的_id。现在,如果我同步它们,第一个寄存器将创建文档,第二个寄存器将插入(并因此覆盖)我的文档。

的解决方案

电流

为了防止我当前将原始_id保存在字段refId下,这非常糟糕,因为我无法使用主寄存器上的所有引用和大多数函数。

选项I - 自动增量

我计划切换到自动增量_ids,但我读到如果您计划扩展,这是您不应该做的事情:

https://blog.serverdensity.com/switching-to-mongodb-and-auto-increment/ https://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/

选项II - 修改子寄存器_id

我已经保存了我的文档来自哪个子寄存器。因此,我可以检查_id是否存在,但是有另一个子寄存器。如果是这样,我可以为新文档生成新的_id,并将新的_id返回到我的子寄存器。这听起来很容易乍一看,但我的文档中有很多引用。

问题)

使用可能的重复ID处理此问题的好方法是什么?是否有一种更简单但有效的方法来解决这个问题?例如。自动为24位数字ObjectId添加前缀。

2 个答案:

答案 0 :(得分:1)

As it is unlikely(虽然并非不可能)在不同的子寄存器中生成两个相同的ObjectId,您可以在错误处理程序中处理重复的ObjectIds。如果存在唯一的密钥冲突并且源寄存器中存在差异,则可以生成新的ObjectId。由于不会频繁调用错误处理程序,因此可以添加更复杂的逻辑而不会影响整体性能。

例如,您可以通过克隆源记录并删除原始文件来生成新的ObjectId,或者,您也可以创建自己的ObjectId并将machineId替换为registerId。

答案 1 :(得分:0)

最终的解决方案是创建一个自定义的猫鼬ObjectId。正如本文https://docs.mongodb.org/manual/reference/object-id/#ObjectIDs-BSONObjectIDSpecification中所提到的,猫鼬_id由几个部分组成,即使它们在不同的机器上生成,也不太可能发生两个_id碰撞。为了更好地控制此过程,我可以控制_id中的processId部分。每个子寄存器都有自己的processID。

为了达到这个目的,我生成了两个函数:

1)检查_id的覆盖值是否可用,有效以及寄存器是否为本地寄存器(主寄存器不需要修改)。条目仅在我的本地注册中生成。

2)修改_id

mongoose = require('mongoose')
ObjectId = mongoose.Types.ObjectId
registerType = require('./register-config.js').getType()#function gives back local/national

exports.useProcessId = ()->
  return process.env.REGISTER_PROCESS_ID? && process.env.REGISTER_PROCESS_ID.length == 4 && registerType == 'local'

exports.changeMongooseId = (data, next) ->
  id = data._id.toString()
  data._id = new ObjectId(id.slice(0,6) + process.env.REGISTER_PROCESS_ID + id.slice(10,24))
  return next()

在将新文档保存到集合之前调用此函数:

instituteSchema.pre('save', (next) ->
  data = @
  async.parallel
    eprd: (next)->
      validateEPRD(data, next)
    changeMongooseId: (next)->
      if useProcessId then processIdConfig.changeMongooseId(data, next) else return next()
    (err)->
      return next new Error(err) if err?
      return next()
)

我不需要在更新等方面调用该函数,因为此时它已经具有唯一的_id