Как обойти пропущенные значения в уникальном индексе, используя mongo db? - PullRequest
8 голосов
/ 25 августа 2011

В документации mongo говорится, что «при сохранении документа в коллекцию с уникальными индексами любые отсутствующие индексированные ключи будут вставлены с нулевыми значениями. Таким образом, будет невозможно вставить несколько документов без одного и того же индексированного ключа. «

Так нельзя ли создать уникальный индекс для необязательного поля? Должен ли я создать составной индекс, скажем, также userId, чтобы решить эту проблему? В моем конкретном случае у меня есть пользовательская коллекция, которая имеет необязательный встроенный объект oauth. например,

>db.users.ensureIndex( { "name":1, "oauthConnections.provider" : 1, "oauthConnections.providerId" : 1 } );

Мой пример пользователя

{  name: "Bob"
   ,pwd: "myPwd"
   ,oauthConnections [
      {
         "provider":"Facebook",
         "providerId" : "12345",
         "key":"blah"
      }
     ,{
         "provider":"Twitter",
         "providerId" : "67890",
         "key":"foo"
      }
     ]
}

Ответы [ 3 ]

11 голосов
/ 26 августа 2011

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

Предупреждение : это невозможно при составных индексах.Я не совсем уверен в вашем вопросе.Вы цитируете часть документации, которая касается составных индексов - там будут вставлены пропущенные значения, но из вашего вопроса, я думаю, вы не ищете решение с составными индексами?

Вот пример:

> db.Test.insert({"myId" : "1234", "string": "foo"});
> show collections
Test
system.indexes
>
> db.Test.find();
{ "_id" : ObjectId("4e56e5260c191958ad9c7cb1"), "myId" : "1234", "string" : "foo" }
>

> db.Test.ensureIndex({"myId" : 1}, {sparse: true, unique: true});
>
> db.Test.insert({"myId" : "1234", "string": "Bla"});
E11000 duplicate key error index: test.Test.$myId_1  dup key: { : "1234" }
>
> db.Test.insert({"string": "Foo"});
> db.Test.insert({"string": "Bar"});
> db.Test.find();
{ "_id" : ObjectId("4e56e5260c191958ad9c7cb1"), "myId" : "1234", "string" : "foo" }
{ "_id" : ObjectId("4e56e5c30c191958ad9c7cb4"), "string" : "Foo" }
{ "_id" : ObjectId("4e56e5c70c191958ad9c7cb5"), "string" : "Bar" }

Также обратите внимание, что составные индексы не могут быть разреженными

2 голосов
/ 25 августа 2011

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

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

1 голос
/ 25 августа 2011

Нет хорошего способа уникального индексирования необязательного поля. Вы можете либо заполнить его значением по умолчанию (_id для пользователя будет работать), позволить своему уровню доступа обеспечить уникальность, либо немного изменить свою «схему».

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

---- редактировать ----

Как показывают другие ответы, вы можете достичь этого с разреженным индексом. Это даже документированное использование. Возможно, вам следует принять один из этих ответов вместо моего.

http://www.mongodb.org/display/DOCS/Indexes#Indexes-SparseIndexes

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