是否可以在两个不同的集合中生成重复的Mongo ObjectId?

Ant*_*ack 169 database mongodb nosql

是否可以为两个不同集合中的文档生成相同的Mongo ObjectId?我意识到这绝对不太可能,但有可能吗?

没有太具体,我问的原因是,通过我正在处理的应用程序,我们会显示当选官员的公开个人资料,我们希望将其转换为我们网站的完全成熟用户.我们为用户和当前不是我们网站成员的当选官员提供单独的收藏.还有各种其他文件,其中包含有关当选官员的各种数据,这些数据都使用他们选出的官方ObjectId映射回该人.

创建帐户后,我们仍然会突出显示与当选官员相关联的数据,但他们现在也是用户集合的一部分,并且相应的用户ObjectId将其配置文件映射到与我们的应用程序的交互.

几个月前我们已经开始将我们的应用程序从MySql转换为Mongo,当我们处于转换状态时,我们存储了这两种数据类型的遗留MySql id,我们现在也开始将选定的官方Mongo ObjectId存储在用户中文件,以映射回选定的官方数据.

我正在考虑将新用户ObjectId指定为先前选定的官方ObjectId,以使事情变得更简单,但是想确保不可能与任何现有用户ObjectId发生冲突.

感谢您的见解.

编辑:发布此问题后不久,我意识到我提出的解决方案不是一个好主意.最好只保留我们现有的架构,并链接到用户文档中选定的官方'_id'.

Raj*_*ani 298

简答

只是添加对您的初始问题的直接响应:是,如果您使用BSON对象ID生成,那么对于大多数驱动程序,ID几乎肯定会在集合中是唯一的.请参阅下文"几乎可以肯定"的含义.

答案很长

Mongo DB驱动程序生成的BSON对象ID很可能在集合中是唯一的.这主要是因为ID的最后3个字节,对于大多数驱动程序,它是通过静态递增计数器生成的.该计数器与收集无关; 它是全球性的.例如,Java驱动程序使用随机初始化的静态AtomicInteger.

那么,为什么在Mongo文档中,他们是否说"ID很可能"是唯一的,而不是直截了当地说它们将是独一无二的?如果您没有获得唯一ID,可能会出现三种可能性(如果有更多信息,请告诉我们):

在此讨论之前,请回想一下BSON对象ID包括:

[自epoch以来的4个字节,3个字节的机器哈希,2个字节的进程ID,3个字节的计数器]

以下是三种可能性,因此您可以自己判断获得欺骗的可能性:

1)计数器溢出:计数器中有3个字节.如果你碰巧在同一台机器上,在同一个机器上一秒钟内插入了超过16,777,216(2 ^ 24)个文件,那么你可能会溢出增量计数器字节并最终得到两个共享同一时间的对象ID,机器,过程和计数器值.

2)计数器不递增:一些Mongo驱动程序使用随机数而不是递增计数字节的数字.在这些情况下,有1/16,777,216的机会生成非唯一ID,但仅当这两个ID在同一秒内生成时(即在ID的时间段更新到下一秒之前),在同一秒内生成机器,在同一个过程中.

3)机器和进程散列到相同的值.在某些极不可能的情况下,机器ID和进程ID值可以映射到两个不同机器的相同值.如果发生这种情况,同时两台不同机器上的两个计数器在同一秒内生成相同的值,那么您最终会得到一个重复的ID.

这是需要注意的三个方案.场景1和3似乎不太可能,如果您使用正确的驱动程序,则场景2完全可以避免.您必须检查驱动程序的来源以确定.

  • 你完全忽略了这样一个事实,即在136年内,只要机器哈希,进程ID和计数器都相同,你就会有另一次生成相同的`ObjectId`的镜头. (37认同)
  • @jamylak当问题变得紧急时我们将处理这个问题(表示那些在70年代标准化YYMMDD日期格式的人) (23认同)

mst*_*arn 13

ObjectIds以类似于UUID的方式生成客户端,但具有一些更好的属性,可以存储在数据库中,例如大致增加顺序并免费编码创建时间.对于您的用例而言,关键在于它们旨在保证高概率的唯一性,即使它们是在不同的机器上生成的.

现在,如果您指的是一般的_id字段,我们不需要跨集合的唯一性,因此重用旧的_id是安全的.作为一个具体的例子,如果你有两个集合,colors并且fruits两者都可以同时拥有一个对象{_id: 'orange'}.

如果您想了解有关如何创建ObjectId的更多信息,请参阅以下规范:http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification


Den*_*att 11

如果有人遇到重复的Mongo ObjectID问题,你应该知道,尽管Mongo本身不太可能发生重复,但是在Mongo中可能会有PHP生成重复的_id.

我经常发生这种情况的用例是当我循环遍历数据集并尝试将数据注入集合时.

保存注入数据的数组必须在每次迭代时显式重置 - 即使您没有指定_id值.出于某种原因,INSERT进程将Mongo _id添加到数组中,就像它是一个全局变量一样(即使数组没有全局范围).即使您在单独的函数调用中调用插入,您通常也希望数组的值不会持久地返回到调用函数,这可能会影响您.

有三种解决方案:

  1. 你可以unset()从数组中的_id字段
  2. array()每次循环遍历数据集时,都可以重新初始化整个数组
  3. 您可以自己明确定义_id值(注意以自己不生成重复的方式定义它).

我的猜测是这是PHP界面中的一个错误,而不是Mongo的问题,但是如果遇到这个问题,只需取消设置_id就可以了.

  • 我不明白你在这里描述的场景;也许你可以展示一些展示错误的代码? (3认同)