Доктрина ODM flush() с уникальным ключом

Я использую доктрину ODM для работы с MongoDB. У меня есть документы для сохранения, которые могут время от времени дублировать. Мне нужна только 1 копия каждого события, поэтому я использую хешированный ключ uniq, чтобы событие было только 1.

Поэтому я делаю несколько -> сохраняться ($document); И когда я делаю ->flush();

Я получаю исключение: localhost:27017: индекс ошибки повторяющегося ключа E11000: dbname.event.$ EventKey_1 dup ключ: {: "keyValue" }

И все данные никогда не сохранялись в MongoDB. Вопрос в том, можно ли сохранить уникальные данные и игнорировать существующие, не выполняя:

try {
    ->persist();
    ->flush();
} catch (\Exception $e) {}

за каждый документ?

Спасибо.

Обновлено: спасибо за ваши ответы и ваше время, но я нашел точное решение:)

Функция вставки Монго имеет опцию "упорядочено:" https://docs.mongodb.org/manual/reference/method/db.collection.insert/ которая позволяет продолжить вставку даже после ошибок.

Доктрина использует расширение Pecl для Монго. doctrine flush() использует этот метод: http://www.php.net/manual/en/mongocollection.batchinsert.php который имеет опцию continueOnError

Так что, если вы делаете это так:

$documentManager->flush(null, ['continueOnError' => true]);

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

Что-то вроде этого:)

2 ответа

Нативные методы Doctrine не поддерживают фильтрацию уникальных значений - вам нужно сделать это самостоятельно. Чтобы вставить эти данные без каких-либо ошибок, вам нужно сделать несколько вещей, в зависимости от структуры вашей сущности:

  1. Найдите все существующие объекты с уникальными ключами, которые у вас есть

  2. Найдите уникальные ключи, которые дублируются между сущностями, которые вы пытаетесь сохранить

  3. Замените уже существующие сущности найденными вами сущностями.

  4. Упорство и флеш

Нет абсолютно никаких шансов сделать это без хотя бы одного дополнительного запроса. Если бы у вас был первичный ключ существующих сущностей, вы могли бы использовать их для получения ссылочного объекта. Но, к сожалению, не поддерживается получение ссылок по уникальным ключам в соответствии с документацией доктрины:

http://doctrine-orm.readthedocs.org/en/latest/reference/limitations-and-known-issues.html

Невозможно использовать столбцы соединения, указывающие на неосновные ключи. Doctrine будет считать, что это первичные ключи, и будет создавать прокси с отложенной загрузкой данных, что может привести к неожиданным результатам. Doctrine может из соображений производительности не проверять правильность этих настроек во время выполнения, а только с помощью команды Validate Schema.

Я не смог получить ['continueOnError' => true] работать, поэтому решил по другому:

$collection = $documentManager->getDocumentCollection(Content::class);
try {
    $collection->insertMany($arrayData, ['ordered' => false]);
} catch (BulkWriteException $exception) {
    // ignore duplicate key errors
    if (false === strpos($exception->getMessage(), 'E11000 duplicate key error')) {
        throw $exception;
    }
}

Вы можете просто сделать: Найти свой существующий идентификатор, отредактировать его и сохранить.

  • С Учением + Symfony:

    $Document = $EntityManager->getRepository("ExpBundle:Document")->find(123);
    $Document->setTitile("Doc");  
    $EntityManager->flush();
    
  • С доктриной

    $Document = $EntityManager->find('Document', 1234);  
    $Document->setTitle("edited");  
    $EntityManager->flush();
    
Другие вопросы по тегам