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

MongoDB: уникальный индекс для свойства элемента массива

У меня есть структура, подобная этой:

class Cat {
  int id;
  List<Kitten> kittens;
}

class Kitten {
  int id;
}

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

db.Cats.ensureIndex({'id': 1, 'kittens.id': 1}, {unique:true})

Но когда я пытаюсь вставить плохо отформатированную кошку, Монго ее принимает.

Я что-то упустил? может ли это быть сделано?

4b9b3361

Ответ 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"
}