MongoDB Уникальный составной индекс позволяет дублировать - PullRequest
0 голосов
/ 01 мая 2020

Я использую PyMon go и PyMODM для работы с довольно простой структурой документа.

Вот как выглядит моя модель:

class User(MongoModel):
    subscriber_uid: fields.CharField = fields.CharField(required=True)
    interface: fields.CharField = fields.CharField(required=True)
    ...other fields...

    class Meta:
        """Defines MongoDB options for this model"""
        cascade = True  # currently nothing to cascade deletes against
        indexes = [
            IndexModel(
                keys=[('subscriber_uid', pymongo.ASCENDING),
                      ('interface', pymongo.ASCENDING)],
                unique=True,
            ),
        ]

Мой модульный тест выглядит так обратите внимание, что DB - это API, который упаковывает фактические команды PyMon go. Например: put_user упаковывает user.save() в некоторых логах обработки исключений c, а read_user упаковывает User.objects.get().

...
    user = User(**TEST_USER)
    user.interface = '2/2/2/2'
    user.subscriber_uid = 'some other suid'
    DB.put_user(user)
    user_from_db = DB.read_user(subscriber_uid=user.subscriber_uid,
                                interface=user.interface)
    assert user_from_db.interface == user.interface
    assert user_from_db.subscriber_uid == user.subscriber_uid

    # attempt to create a new record with a non-unique suid+iface pair
    # ie: ensure this updates instead of creates
    user = User(**TEST_USER)
    user.someotherattr = 1023
    DB.put_user(user)
    user_from_db: User = DB.read_user(subscriber_uid=user.subscriber_uid,
                                      interface=user.interface)
    assert user_from_db.seed_index == user.seed_index
...

Когда я запускаю этот тест, read_user() / User.objects.get() вызов завершается с ошибкой MultipleObjectsReturned возвращаемым объектам, и я могу подтвердить, что есть две записи с одинаковыми значениями interface и subscriber_uid.

Из того, что я видел в других ответах StackOverflow и comments , составной уникальный индекс выше должен предотвратить это.

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

1 Ответ

0 голосов
/ 02 мая 2020

Очевидным недостатком индекса была красная сельдь.

Состояние документов PyMODM :

Обратите внимание, что connect () должен быть вызван (определяя соответствующий псевдоним соединения, если таковой имеется), прежде чем любой MongoModel может быть использован с этим псевдонимом. Если для Meta определены индексы, то это должно быть до оценки класса MongoModel.

Я использовал функцию для инициирования соединения с MongoDB, что, конечно, произошло после того, как я импортировал классы модели. , Для других клиентов баз данных это обычно будет путь к go, если вы не уверены, будет ли доступна ваша БД при импорте модуля (обычно для контейнерных рабочих нагрузок, запуск приложения обычно занимает меньше времени, чем запуск БД). Клиент PyMon go является особенным, хотя :

Начиная с версии 3.0, конструктор MongoClient больше не блокирует соединение с сервером или серверами и больше не вызывает ConnectionFailure, если они недоступны, ни ConfigurationError, если учетные данные пользователя неверны. Вместо этого конструктор немедленно возвращается и запускает процесс подключения в фоновых потоках.

Перемещение connect() в начало моего модуля моделей решило проблему. Даже если БД недоступна, когда вызывается connect(). Как только база данных становится доступной, индекс создается и все становится правильно в мире.

...