MongoDB: уникальный индекс для свойства элемента массива
У меня есть структура, подобная этой:
class Cat {
int id;
List<Kitten> kittens;
}
class Kitten {
int id;
}
Я хочу запретить пользователям создавать кошку с более чем одним котенком с одним и тем же идентификатором. Я попытался создать индекс следующим образом:
db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})
Но когда я пытаюсь вставить плохо отформатированную кошку, Монго ее принимает.
Я что-то упустил? может ли это быть сделано?
Ответы
Ответ 1
Насколько я знаю, уникальные индексы только обеспечивают уникальность в разных документах, поэтому это приведет к дублированию ключевой ошибки:
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
db.cats.insert( { id: 123, kittens: [ { id: 456 } ] } )
Но это разрешено:
db.cats.insert( { id: 123, kittens: [ { id: 456 }, { id: 456 } ] } )
Я не уверен, если какой-либо способ обеспечит ограничение, которое вам нужно на уровне Mongo, возможно, это что-то, что вы могли бы проверить в логике приложения при вставке обновления?
Ответ 2
Обеспечение уникальности отдельных значений в поле массива
В дополнение к приведенному выше примеру в MongoDB есть функция, гарантирующая, что когда вы добавляете новый объект/значение в поле массива, он будет выполнять обновление только в том случае, если значение/объект еще не существует.
Итак, если у вас есть документ, который выглядит так:
{ _id: 123, kittens: [456] }
Это разрешено:
db.cats.update({_id:123}, {$push: {kittens:456}})
в результате чего
{ _id: 123, kittens: [456, 456] }
однако использование функции $addToSet (в отличие от $push) будет проверять, существует ли значение уже до его добавления.
Итак, начиная с:
{ _id: 123, kittens: [456] }
затем выполните:
db.cats.update({_id:123}, {$addToSet: {kittens:456}})
Не будет никакого эффекта.
Итак, длинный рассказ, уникальные ограничения не подтверждают уникальность внутри элементов значения поля массива, просто два документа не могут иметь одинаковые значения в индексированных полях.
Ответ 3
Существует эквивалент вставки с атрибутом uniquness в массиве. Следующая команда, по существу, вставляет, сохраняя уникальность котят (upsert создает ее для вас, если объект с 123 еще не существует).
db.cats.update(
{ id: 123 },
{ $addToSet: {kittens: { $each: [ 456, 456] }}, $set: {'otherfields': 'extraval', "field2": "value2"}},
{ upsert: true}
)
Результирующее значение объекта будет
{
"id": 123,
"kittens": [456],
"otherfields": "extraval",
"field2": "value2"
}