Как обновить встроенные документы в Doctrine MongoDB?

6

У меня есть документ с встроенным документом. Когда я создаю объект в первый раз, все работает нормально, но когда я пытаюсь обновить документ, встроенный документ не обновляется.

/** @MongoDB\Document */
class DocumentA
{
    /** @MongoDB\EmbedOne(targetDocument="DocumentB") **/
    protected $docB;

    /** @MongoDB\String */
    protected $valueA;
}

/** @MongoDB\EmbeddedDocument */
class DocumentB
{
    /** @MongoDB\String */
    protected $valueB;
}

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

// Variant A – Does not work
$document = ... // find from data store
$document->setValueA('Hello World');
$document->getDocB()->setValueB('foo baz');

$om->persist($document);
$om->flush();

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

// Variant B - Does work
$document = ... // find from data store
$document->setValueB('Hello World 2');
$document->setDocB(new DocumentB());
$document->getDocB()->setValueB('foo baz 2');

$om->persist($document);
$om->flush();

Как я уже сказал, вариант B отлично работает. Однако в моем приложении документы сложнее, и для меня было бы нецелесообразно создавать новый объект для встроенного документа каждый раз, когда я должен его обновлять. Есть ли способ сообщить Doctrine ODM посмотреть значения встроенного документа, чтобы решить, нужно ли его обновлять?

Теги:
doctrine
doctrine-odm

2 ответа

2

Я столкнулся с такой же проблемой. Оказывается, UnitOfWork, кажется, терпит неудачу при вычислении наборов документов с другими встроенными документами, хотя я не смог понять, почему... В результате, когда я сравниваю фактическое значение и оригинал, единица работы показывает одно и то же значение для обоих. Говоря с вашим вариантом А, когда вы

$document->getDocB()->setValueB('foo baz');

Единица работы показывает "foo baz" как для старого, так и для нового значения и не будет распознавать ее как изменение и не будет ее обновлять.

В любом случае, это приводит к обходному пути:

$document = ... // find from data store
$document->setValueA('Hello World');
$docB = $document->getDocB();
$docB->setValueB('foo baz');
$om->detach($docB);
$om->persist($document);
$om->flush();

Это заставляет блок работы распознавать документ docB документа $в качестве вновь установленного документа и будет очищать его, как ожидалось.

  • 0
    У меня возникли проблемы с заменой внедренного документа другим. В моем случае DocumentB - это не EmbeddedDocument, а скорее Document. Использование detach на объекте, как вы показали здесь, работало и в этом сценарии.
0

MongoDB имеет только атомные операции. У вас есть варианты: 1. Запросите документ, найдите подходящий поддокумент, обновите весь документ или его часть. Плюсы: простая логика Минусы: неатомные 2. Используйте оператор positional $, ваш поддокументы находятся в списке.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню