Разница между хранением ObjectId и его строковой формы в MongoDB

Меня немного смущает использование Mongo DB ObjectIds. Конечно, они отлично подходят для создания идентификаторов на стороне клиента, которые почти наверняка не конфликтуют с другими идентификаторами, созданными на стороне клиента. Но монго, похоже, хранит их каким-то особым образом. Хранение строкового представления идентификатора отличается от хранения идентификатора объекта как объекта. Почему это?

Разве строковая форма не содержит той же информации, что и объектная форма? Почему монго так старается различать эти две формы? Меня смущает, когда я пытаюсь сравнить _ids, например, отправленные из внешнего интерфейса. Моя база данных никоим образом не согласуется с тем, хранит ли она идентификаторы строковой формы или идентификаторы объектной формы, и хотя мой код, безусловно, частично виноват, я в основном виню монго за то, что он сделал это таким странным.

Я ошибаюсь, что это странно? Почему монго делает это именно так?


person B T    schedule 12.01.2015    source источник


Ответы (2)


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

Следует отметить, что между ObjectId (http://docs.mongodb.org/manual/reference/object-id/) и его шестнадцатеричное представление на самом деле имеет 12 байтов разницы, ObjectId составляет 12 байтов, а его шестнадцатеричное представление равно 24.

Речь идет не только об эффективности хранения, но и об индексах; не только потому, что они меньше, но и потому, что ObjectId можно использовать особым образом, чтобы гарантировать загрузку только части индекса; части, которые используются. Это становится наиболее заметным при вставке, когда для обеспечения уникальности необходимо загрузить только последнюю часть этого индекса. Вы не можете гарантировать такое поведение с его шестнадцатеричным представлением.

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

person Sammaye    schedule 12.01.2015
comment
Вам не нужно преобразовывать ObjectId в строки для их сравнения. У них есть метод equals (по крайней мере, в mongo native/mongoskin). - person B T; 12.01.2015
comment
В вашей ссылке говорится, что ObjectIds составляют 12 байтов, а не 16. - person B T; 12.01.2015
comment
@BT упс, мой плохой, должно быть, я думал о чем-то другом - person Sammaye; 12.01.2015
comment
@BT, если фреймворк поддерживает это, тогда это блестяще, я лично использую PHP - person Sammaye; 12.01.2015
comment
Согласно stackoverflow.com/a/27274609/6440033, строковое представление ObjectId должно быть 29 байт (24 * UTF8 -закодированные символы низкого диапазона, поэтому однобайтовые каждый + длина 4 байта + символ завершения строки 1 байт) - person dnickless; 10.10.2019

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

Вы можете переформатировать всю свою БД и использовать единое поле _id, чтобы решить эту проблему и убедиться, что ваш код сохраняется в том же формате. ObjectId быстро генерируются MongoDB, поэтому я бы использовал это при создании новых документов.

person bakkal    schedule 12.01.2015
comment
А, значит, все дело в эффективности хранения? Все мои _ids являются ObjectIds, но многие ссылочные поля сейчас не те, я полагаю, мне следует все исправить - person B T; 12.01.2015
comment
Размер поля также может повлиять на производительность индексации/запросов (не уверен, насколько сильно для ObjectId по сравнению с ObjectId.str, но MongoDB, вероятно, был построен/протестирован с ObjectId, так что давайте использовать это: D) - person bakkal; 12.01.2015
comment
На самом деле это довольно раздражает, поскольку нет действительно хорошего способа сериализовать идентификаторы объектов. Любые запросы, поступающие от клиента, должны быть явно прочесаны, чтобы заменить строковые идентификаторы идентификаторами объектов. Есть ли способ обойти это? - person B T; 12.01.2015
comment
Зависит от вашего веб-стека/фреймворка, поскольку он включает в себя клиента, поэтому я бы опубликовал отдельный вопрос с подробностями. - person bakkal; 12.01.2015
comment
Теоретически не мог ли монго (клиент или сервер) определить, когда строка является допустимым шестнадцатеричным значением ObjectId, и автоматически преобразовать ее? Тогда пользователю не нужно будет различать, и единственными накладными расходами будут незначительные затраты на десериализацию/сериализацию. - person B T; 12.01.2015
comment
Это открывает вам возможность случайного преобразования случайной строки, которая по чистой случайности проходит как допустимый ObjectId, когда вы фактически планировали, что _id будет строкой (что MongoDB допускает в качестве варианта использования). Вы принимаете этот путь за борт. Когда вы используете первичные ключи в качестве последовательного целого числа в MySQL или PostgreSQL, вы вводите целые числа, такие как 12345, а не 12345 в виде строки. MongoDB не может угадать ваш вариант использования, поскольку вы не определяете схему, как в СУБД, и не запрашиваете автоматическое преобразование. РСУБД могут, потому что вы предварительно определяете схему. В MongoDB эти вещи остаются в вашем стеке (например, веб/клиент). - person bakkal; 13.01.2015
comment
Это может относиться и к другим полям/типам, а не только к _id, например. даты, строки и даты (например, ISODate) не следует путать. Эти обязанности обычно входят в ваш верхний стек, например. интерфейс REST, который имеет некоторое представление о том, чего ожидать (например, неявно через определение схемы или явные преобразования в зависимости от вашего стиля кодирования) - person bakkal; 13.01.2015
comment
Пока mongo преобразует все objectid обратно в строки, не будет проблем со случайным преобразованием случайных строк. Но точка взята - person B T; 13.01.2015
comment
Я думаю, что mongoose для node.js автоматически преобразует эти строки, по крайней мере, в некоторых случаях (например, при поиске по _id он преобразует вашу строку в ObjectId для вас). Вопрос: Представим, что у меня есть поле в какой-то схеме, и, скажем, оно называется author_id, что соответствует пользователю, написавшему этот пост или отзыв или что-то в этом роде. Лучше сделать это поле типом ObjectId или String? (Пожалуйста, учтите, что это также будет индексом). - person Will Brickner; 04.05.2017
comment
(Я использую мангуст, который использует схемы, не уверен, что это уместно здесь) - person Will Brickner; 04.05.2017