Подтвердить что ты не робот

MongoDB: уникальный ключ во встроенном документе

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

У меня есть коллекция 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 }

Любые предложения? Спасибо!

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

Затем создайте такой индекс:

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

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

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

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

Ответ 3

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

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

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

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

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

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

Ответ 4

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

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

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

Ответ 5

Вы можете использовать функцию 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/. Проверьте это.