Как установить уникальное ограничение для поля в документе, вложенном в массив? - PullRequest
2 голосов
/ 07 мая 2020

У меня есть набор документов в MongoDB, который выглядит так:

{"_id": 1, "array": [{"id": 1, "content": "..."}, {"id": 2, "content": "..."}]}
{"_id": 2, "array": [{"id": 1, "content": "..."}, {"id": 2, "content": "..."}, {"a_id": 3, "content": "..."}]}

, и я хочу убедиться, что в каждом документе нет дубликатов array.id. Итак, приведенный пример в порядке, но следующий - нет:

{"_id": 1, "array": [{"id": 1, "content": "..."}, {"id": 1, "content": "..."}]}

Мой вопрос в том, как это сделать (желательно в PyMongo).

EDIT

Я пробовал следующий код, который, как я думал, создаст ключ на (_id, array.id), но если вы его запустите, этого не произойдет:

from pymongo import MongoClient, ASCENDING

client = MongoClient(host="localhost", port=27017)
database = client["test_db"]
collection = database["test_collection"]
collection.drop()

collection.create_index(keys=[("_id", ASCENDING),
                              ("array.id", ASCENDING)],
                        unique=True,
                        name="new_key")

document = {"array": [{"id": 1}, {"id": 2}]}
collection.insert_one(document)

collection.find_one_and_update({"_id": document["_id"]},
                               {"$push": {"array": {"id": 1}}})

updated_document = collection.find_one({"_id": document["_id"]})

print(updated_document)

, который выводит (обратите внимание, что есть два объекта с id = 1 в array). Я ожидал бы исключения.

{'_id': ObjectId('5eb51270d6d70fbba739e3b2'), 'array': [{'id': 1}, {'id': 2}, {'id': 1}]}

1 Ответ

1 голос
/ 09 мая 2020

Итак, если я правильно понимаю, нет способа, как установить индекс (или какое-то условие), которое обеспечило бы уникальность в документе, верно? (Кроме того, явно отметьте это при создании документа или при вставке в него.)

Да. См. Следующие два сценария ios об использовании уникального индекса в поле массива со встроенными документами.

Уникальный многоклавишный индекс (индекс в поле встроенного документа в массиве):

Для уникальных индексов ограничение уникальности применяется к отдельным документам в коллекции, а не к одному документу.

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


Первый сценарий:

db.arrays.createIndex( { _id: 1, "array.id": 1}, { unique: true } )

db.arrays.insertOne( { "_id": 1, "array": [ { "id": 1, "content": "11"}, { "id": 2, "content": "22"} ] } )

db.arrays.insertOne( { "_id": 2, "array": [ { "id": 1, "content": "1100"}, { "id": 5, "content": "55"} ] } )

db.arrays.insertOne( {"_id": 3, "array": [ {"id": 3, "content": "33"}, {"id": 3, "content": "3300"} ] } )

Все три документа вставляются без ошибок.

Согласно примечанию к Уникальный многоклавишный индекс , выше, документ с _id : 3 имеет два встроенных документа в массиве с одинаковым значением "array.id": 3.

Кроме того, уникальность применяется к t два ключа составного индекса { _id: 1, "array.id": 1}, а также в документах были повторяющиеся "array.id" значения (_id значения 1 и 2).


Второй сценарий :

db.arrays2.createIndex( { "array.id": 1 }, { unique: true } )

db.arrays2.insertOne( { "_id": 3, "array": [ { "id": 3, "content": "33" }, { "id": 3, "content": "330"} ] } )
db.arrays2.insertOne( { "_id": 4, "array": [ { "id": 3, "content": "331" }, { "id": 30, "content": "3300" } ] } )

Первый документ с _id : 3 успешно вставлен. У второго ошибка: "errmsg" : "E11000 duplicate key error collection: test.arrays2 index: array.id_1 dup key: { array.id: 3.0 } ". Такое поведение соответствует примечанию Уникальный многоклавишный индекс .

...