MongoDB自定义和唯一ID

时间:2011-01-10 18:55:12

标签: mongodb

我正在使用MongoDB,我想为博客帖子(将在宁静的URL中使用)生成唯一的和加密的ID,例如 s52ruf6wst xR2ru286zjI

您认为什么是最好的,以及生成这些ID的更具伸缩性的方式?

我在考虑以下架构:

  • 定期(每日?)批处理运行以生成大量随机和唯一ID,并将它们插入到具有InsertIfNotPresent的专用MongoDB集合中
  • 每次我想要生成一篇新博文时,我会从这个集合中获取一个ID,并使用UpdateIfCurrent原子操作将其标记为“已采取”

WDYT?

5 个答案:

答案 0 :(得分:32)

这正是MongoDB的开发人员以他们的方式构建他们的ObjectID(_id)的原因...... 跨节点扩展等。

  

BSON ObjectID是12字节的值   由4字节时间戳组成   (自纪元以来的秒数),一个3字节   machine id,一个2字节的进程id和a   3字节计数器。请注意   时间戳和计数器字段必须是   与其余的不同,存储大端   BSON。这是因为他们是   逐字节比较,我们想要   确保大多增加订单。   这是架构:

0123   456      78    91011
time   machine  pid   inc
  

传统数据库经常使用   单调递增序列   主键的数字。在MongoDB中,   首选方法是使用   而是对象ID。对象ID是   与分片和分辨率更具协同作用   分布。

http://www.mongodb.org/display/DOCS/Object+IDs

所以我只想使用ObjectID的

转换为字符串时它们并没有那么糟糕(这些字符串是在彼此之后插入的)......

例如:

4d128b6ea794fc13a8000001
4d128e88a794fc13a8000002

他们看起来乍一看是“可猜测的”,但他们真的不容易猜到......

4d128 b6e a794fc13a8000001
4d128 e88 a794fc13a8000002

对于一个博客,我不认为这是一个很大的交易...我们在整个地方使用它。

答案 1 :(得分:3)

使用UUID怎么样?

http://www.famkruithof.net/uuid/uuidgen作为示例。

答案 2 :(得分:1)

创建一个返回全局唯一ID的Web服务,以便您可以让许多Web服务器参与并知道您不会遇到任何重复项?

如果您的每日批次没有分配足够的物品?你中午跑吗?

我将Web服务客户端实现为一个队列,可以由本地进程查看并根据需要重新填充(当服务器较慢时)并且可以在队列中保留足够的项目而不需要在高峰使用期间运行。有意义吗?

答案 3 :(得分:0)

这是一个老问题,但对于那些可能正在寻找其他解决方案的人来说。

一种方法是使用简单快速的替换密码。 (下面的代码基于别人的代码 - 我忘记了从哪里取出它所以无法给予适当的信任。)

class Array
  def shuffle_with_seed!(seed)
    prng = (seed.nil?) ? Random.new() : Random.new(seed)
    size = self.size

    while size > 1
      # random index
      a = prng.rand(size)

      # last index
      b = size - 1

      # switch last element with random element
      self[a], self[b] = self[b], self[a]

      # reduce size and do it again
      size = b;
    end

    self
  end

  def shuffle_with_seed(seed)
    self.dup.shuffle_with_seed!(seed)  
  end
end

class SubstitutionCipher

  def initialize(seed)
    normal = ('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + [' ']
    shuffled = normal.shuffle_with_seed(seed)
    @map = normal.zip(shuffled).inject(:encrypt => {} , :decrypt => {}) do |hash,(a,b)|
      hash[:encrypt][a] = b
      hash[:decrypt][b] = a
      hash
    end
  end

  def encrypt(str)
    str.split(//).map { |char| @map[:encrypt][char] || char }.join
  end

  def decrypt(str)
    str.split(//).map { |char| @map[:decrypt][char] || char }.join
  end

end

你这样使用它:

MY_SECRET_SEED = 3429824

cipher = SubstitutionCipher.new(MY_SECRET_SEED)

id = hash["_id"].to_s
encrypted_id = cipher.encrypt(id)
decrypted_id = cipher.decrypt(encrypted_id)

请注意,它只会加密a-z,A-Z,0-9和一个空格,使其他字符保持不变。对于BSON ID来说已经足够了。

答案 4 :(得分:-1)

“正确”的答案,实际上不是一个很好的解决方案恕我直言,是生成一个随机ID,然后检查数据库是否有冲突。如果是碰撞,请再次进行。重复,直到找到未使用的匹配。大多数情况下,第一个将起作用(假设您的生成过程足够随机)。

应该注意的是,只有当您担心基于时间的UUID或基于计数器的ID的安全隐患时,才需要此过程。这些中的任何一个都将导致“可猜测性”,这在任何给定情况下可能是也可能不是问题。我会考虑基于时间或基于计数器的ID足以用于博客帖子,但我不知道您的情况和推理的详细信息。