MongoDB: уникальный ключ во встроенном документе - PullRequest
17 голосов
/ 14 декабря 2010

Можно ли установить уникальный ключ для ключа во встроенном документе?

У меня есть коллекция Users со следующими образцами документов:

 {
       Name: "Bob",
       Items: [
           {
               Name: "Milk"
           },
           {
               Name: "Bread"
           }
       ]
    },
    {
       Name: "Jim"
    },

Есть ли способ создать индекс по свойству Items.Name?

При попытке создать индекс я получил следующую ошибку:

> db.Users.ensureIndex({"Items.Name": 1}, {unique:true});
E11000 duplicate key error index: GroceryGuruApp.Users.$Items.Name_1  dup key: {
 : null }

Есть предложения? Спасибо!

Ответы [ 5 ]

22 голосов
/ 14 декабря 2010

Уникальные индексы существуют только для всей коллекции.Чтобы обеспечить уникальность и другие ограничения в документе, вы должны сделать это в коде клиента.(Вероятно, виртуальные коллекции позволят это сделать, вы можете проголосовать за это.)

В вашем случае вы пытаетесь создать индекс по ключу Items.Name, который не существуетв любом из документов (он не относится к внедренным документам внутри массива Items), поэтому он null и нарушает уникальное ограничение для всей коллекции.

7 голосов
/ 15 августа 2011

Вы можете создать уникальный составной разреженный индекс , чтобы выполнить то, что вы ожидаете. Возможно, это не лучший вариант (клиентская сторона все еще может быть лучше), но он может выполнять то, что вы просите, в зависимости от конкретных требований.

Чтобы сделать это, вам нужно создать еще одно поле на том же уровне, что и Name: Bob, уникальное для каждой записи верхнего уровня (можно указать FirstName + LastName + Address, мы назовем этот ключ Identifier ).

Затем создайте индекс, подобный этому:

ensureIndex({'Identifier':1, 'Items.name':1},{'unique':1, 'sparse':1})

Разреженный индекс будет игнорировать элементы, у которых нет поля, поэтому это должно решить вашу ключевую проблему NULL. Объединение вашего уникального идентификатора и Items.name в качестве составного уникального индекса должно гарантировать, что вы не можете иметь одно и то же имя элемента дважды на человека.

Хотя я должен добавить, что я работаю с Монго всего пару месяцев, и моя наука может быть отключена. Это основано не на эмпирических данных, а на наблюдаемом поведении.

Подробнее об индексах MongoDB

3 голосов
/ 14 декабря 2010

Индекс будет для всех пользователей, и, поскольку вы запросили его «уникальный», ни один пользователь не сможет иметь два элемента с одинаковыми именами, И никакие два пользователя не смогут иметь элемент с одинаковым именем.

Это то, что вы хотите?

Кроме того, похоже, что он возражает против двух пользователей, имеющих значение 'null' для Items.Name, ясно, что это делает Джим, есть ли еще такая запись?

Было бы необычно требоватьуникальность в индексированной коллекции, подобной этой.

MongoDB разрешает уникальные индексы, где она индексирует только первое из каждого значения, см. http://www.mongodb.org/display/DOCS/Indexes#Indexes-DuplicateValues,, но я подозреваю, что реальное решение не требует уникальности в этом случае.

Если вы хотите обеспечить уникальность только внутри Предметов для одного пользователя, вы можете попробовать опцию $ addToSet.См http://www.mongodb.org/display/DOCS/Updating#Updating-%24addToSet

2 голосов
/ 14 декабря 2010

Альтернативой может быть моделирование элементов в виде хэша с именем элемента в качестве ключа.

Items: { "Milk": 1, "Bread": 1 }

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

1 голос
/ 20 марта 2013

Вы можете использовать findAndModify для создания функции последовательности / счетчика.

function getNextSequence(name) {
   var ret = db.counters.findAndModify({
        query: { _id: name },
        update: { $inc: { seq: 1 } },
        new: true,
        upsert: true
    });
    return ret.seq;
}

Затем используйте его всякий раз, когда нужен новый идентификатор ...

db.users.insert({
    _id: getNextSequence("userid"),
    name: "Sarah C."
})

Это из http://docs.mongodb.org/manual/tutorial/create-an-auto-incrementing-field/. Проверьте это.

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