Возможность создания дубликата Mongo ObjectId в двух разных коллекциях? - PullRequest
164 голосов
/ 13 января 2011

Возможно ли сгенерировать один и тот же объектный идентификатор Mongo для документа в двух разных коллекциях?Я понимаю, что это определенно очень маловероятно, но возможно ли это?

Не вдаваясь в подробности, я спрашиваю, потому что с приложением, над которым я работаю, мы показываем публичные профили избранных должностных лиц, которых мы надеемся превратить в полноправных пользователей нашего сайта.У нас есть отдельные коллекции для пользователей и выборных должностных лиц, которые в настоящее время не являются членами нашего сайта.Существуют различные другие документы, содержащие различные фрагменты данных об избранных должностных лицах, которые все сопоставляются с лицом, использующим их избранный официальный ObjectId.

После создания учетной записи мы по-прежнему выделяем данные, связанные с избранным официальным лицом, но онитеперь мы также являемся частью коллекции пользователей с соответствующим ObjectId пользователей, чтобы сопоставить их профиль с взаимодействиями с нашим приложением.

Мы начали преобразовывать наше приложение из MySql в Mongo несколько месяцев назад, и пока мы находимся вПри переходе мы сохраняем унаследованный идентификатор MySql для обоих этих типов данных, и теперь мы также начинаем сохранять выбранный официальный Mongo ObjectId в документе пользователя для сопоставления с избранными официальными данными.

Я размышлял толькоуказав новый пользовательский ObjectId в качестве предыдущего избранного официального ObjectId, чтобы упростить ситуацию, но хотел убедиться, что невозможно столкновение с любым существующим пользовательским ObjectId.

Спасибо за ваше участиезрение.

Редактировать: Вскоре после публикации этого вопроса я понял, что предложенное мной решение не очень хорошая идея.Было бы лучше просто сохранить текущую схему, которая у нас есть, и просто указать ссылку на избранного должностного лица '_id' в документе пользователя.

Ответы [ 4 ]

292 голосов
/ 17 апреля 2011

Краткий ответ

Просто чтобы добавить прямой ответ на ваш первоначальный вопрос: ДА, если вы используете генерацию идентификатора объекта BSON, тогда для большинства драйверов идентификаторыпочти наверняка будут уникальными среди коллекций.Ниже показано, что означает «почти наверняка».

Длинный ответ

Идентификаторы объектов BSON, сгенерированные драйверами Mongo DB, с большой вероятностью будут уникальными среди коллекций.Это происходит главным образом из-за последних 3 байтов идентификатора, который для большинства драйверов генерируется через статический инкрементный счетчик.Этот счетчик не зависит от коллекции;это глобально.Например, драйвер Java использует случайно инициализированный статический AtomicInteger.

Так почему же в монго-документах они говорят, что идентификаторы «очень вероятно» будут уникальными, вместо того, чтобы прямо сказать, что они будут уникальными?Возможны три варианта, когда вы не получите уникальный идентификатор (пожалуйста, дайте мне знать, если их будет больше):

Перед этим обсуждением напомним, что идентификатор объекта BSON состоит из:

[4 байта секунды с начала эпохи, 3 байта машинного хэша, 2 байта идентификатора процесса, 3 байта счетчик]

Вот три варианта, поэтому вы сами решаете, какова вероятность получения дублирования:

1) Переполнение счетчика: в счетчике 3 байта.Если вам случится вставить более 16 777 216 (2 ^ 24) документов за одну секунду на одном и том же компьютере в одном и том же процессе, вы можете переполнить увеличивающиеся байты счетчика и получить два идентификатора объекта, которые совместно используют одно и то же время:, process и значения счетчика.

2) Счетчик без приращения: некоторые драйверы Mongo используют случайные числа вместо приращения чисел для байтов счетчика.В этих случаях существует вероятность 1 / 16,777,216 генерирования неуникального идентификатора, но только в том случае, если эти два идентификатора генерируются в одну и ту же секунду (т. Е. До того, как временной отрезок идентификатора обновляется до следующей секунды), в ту же секундумашина, в том же процессе.

3) Хэш машины и процесса с одинаковыми значениями.Значения идентификатора компьютера и идентификатора процесса могут в некоторых крайне маловероятных сценариях соответствовать одним и тем же значениям для двух разных компьютеров.Если это произойдет, и в то же время два счетчика на двух разных компьютерах в течение одной и той же секунды генерируют одно и то же значение, то в итоге вы получите дубликат ID.

Это три сценарияследить за.Сценарии 1 и 3 кажутся крайне маловероятными, а сценарий 2 можно полностью избежать, если вы используете правильный драйвер.Вы должны будете проверить источник драйвера, чтобы знать наверняка.

13 голосов
/ 13 января 2011

ObjectIds генерируются на стороне клиента способом, аналогичным UUID, но с некоторыми более хорошими свойствами для хранения в базе данных, такими как грубо увеличивающийся порядок и бесплатное кодирование времени их создания.Ключевым моментом для вашего варианта использования является то, что они предназначены для обеспечения высокой вероятности уникальности, даже если они генерируются на разных машинах.

Теперь, если вы обращались к полю _id в целом, нам не требуетсяуникальность среди коллекций, поэтому можно безопасно использовать старый _id.В качестве конкретного примера, если у вас есть две коллекции, colors и fruits, обе могут одновременно иметь объект типа {_id: 'orange'}.

. Если вы хотите узнать больше о том, как создаются ObjectIds, здесьэто спецификация: http://www.mongodb.org/display/DOCS/Object+IDs#ObjectIDs-BSONObjectIDSpecification

11 голосов
/ 17 апреля 2012

В случае, если у кого-то возникают проблемы с дублирующимися объектными идентификаторами Mongo, вы должны знать, что, несмотря на маловероятную ошибку, происходящую в самом Mongo, возможно создать дублированные _id с помощью PHP в Mongo.

Случай использования, где это происходило с регулярностью для меня, - это когда я перебираю набор данных и пытаюсь вставить данные в коллекцию.

Массив, содержащий данные внедрения, должен явно сбрасываться на каждой итерации - даже если вы не указываете значение _id. По какой-то причине процесс INSERT добавляет Mongo _id в массив, как если бы он был глобальной переменной (даже если массив не имеет глобальной области видимости). Это может повлиять на вас, даже если вы вызываете вставку в отдельном вызове функции, где вы обычно ожидаете, что значения массива не сохранятся обратно к вызывающей функции.

Для этого есть три решения:

  1. Вы можете unset() поле _id из массива
  2. Вы можете переинициализировать весь массив с помощью array() каждый раз, когда просматриваете набор данных
  3. Вы можете явно определить значение _id самостоятельно (заботясь о том, чтобы определить его таким образом, чтобы вы сами не генерировали дублирование).

Я предполагаю, что это ошибка в интерфейсе PHP, и не такая уж проблема с Mongo, но если вы столкнулись с этой проблемой, просто сбросьте _id, и все будет в порядке.

0 голосов
/ 13 января 2011

Нет никаких гарантий относительно уникальности ObjectId в разных коллекциях.Даже если это маловероятно маловероятно, это будет очень плохой дизайн приложения, основанный на уникальности _id в разных коллекциях.

Это можно легко проверить в оболочке mongo:

MongoDB shell version: 1.6.5
connecting to: test
> db.foo.insert({_id: 'abc'})
> db.bar.insert({_id: 'abc'})
> db.foo.find({_id: 'abc'})
{ "_id" : "abc" }
> db.bar.find({_id: 'abc'})
{ "_id" : "abc" }
> db.foo.insert({_id: 'abc', data:'xyz'})
E11000 duplicate key error index: test.foo.$_id_  dup key: { : "abc" }

Итак, абсолютно не полагайтесь на то, что _id уникален среди коллекций, и поскольку вы не управляете функцией генерации ObjectId, не надейся на это.

Можно создать что-то, что больше похоже на uuid, и если вы сделаете это вручную, у вас будет лучшая гарантия уникальности.

Помните, что вы можете помещать объекты разных «типов» в одну коллекцию, так почему бы просто не поместить ваши две «таблицы» в одну коллекцию.Они будут использовать одно и то же пространство _id и, таким образом, будут гарантированно уникальными.Переключение с «предполагаемого» на «зарегистрированное» было бы простым переключением поля ...

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...