Доктрина 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 не поддерживают фильтрацию уникальных значений - вам нужно сделать это самостоятельно. Чтобы вставить эти данные без каких-либо ошибок, вам нужно сделать несколько вещей, в зависимости от структуры вашей сущности:
Найдите все существующие объекты с уникальными ключами, которые у вас есть
Найдите уникальные ключи, которые дублируются между сущностями, которые вы пытаетесь сохранить
Замените уже существующие сущности найденными вами сущностями.
Упорство и флеш
Нет абсолютно никаких шансов сделать это без хотя бы одного дополнительного запроса. Если бы у вас был первичный ключ существующих сущностей, вы могли бы использовать их для получения ссылочного объекта. Но, к сожалению, не поддерживается получение ссылок по уникальным ключам в соответствии с документацией доктрины:
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();