使用Doctrine MongoDB ODM进行原子操作

Bur*_*rak 5 doctrine mongodb symfony

我似乎无法使用以下查询.基本上,我正在尝试将消息文档添加到对话文档中,如下所示:

public function reply($conversationId, Message $message, $flush = true)
{            
    $this->dm->createQueryBuilder($this->class)
        ->field('archivers')->unsetField()
        ->field('repliedBy')->set($message->getUserId())
        ->field('repliedBody')->set($message->getBody())
        ->field('repliedAt')->set(new \DateTime())
        ->field('modifiedAt')->set(new \DateTime())
        ->field('messages')->push($message)
        ->field('id')->equals(new \MongoId($conversationId))
        ->getQuery()
        ->execute();

    if ($flush) {
        $this->dm->flush();
    }
}
Run Code Online (Sandbox Code Playgroud)

此回复方法以两种方式调用.首先是用户通过html表单发布消息,然后是由Android应用程序发出的REST调用.表单有效,但REST调用失败(其余实现使用带有FOSRestBundle btw的JMSSerializerBundle)...

我已经验证了代码被调用并且传递给方法的参数在两种情况下都是有效的,但由于某种原因,UnitOfWork.php中的commit()调用忽略了对文档的更改.见第413行,看看我的意思.

有没有人知道为什么会这样?

以下是我尝试过的其他方法:

首先,我添加了一个update()调用,该调用因"Catchable Fatal Error:类的对象...无法转换为/vendor/bundles/Symfony/Bundle/DoctrineMongoDBBundle/Logger/DoctrineMongoDBLogger.php第280行"中的字符串而失败.

public function reply($conversationId, Message $message, $flush = true)
{            
    $this->dm->createQueryBuilder($this->class)
        ->update()
        ->field('archivers')->unsetField()
        ->field('repliedBy')->set($message->getUserId())
        ->field('repliedBody')->set($message->getBody())
        ->field('repliedAt')->set(new \DateTime())
        ->field('modifiedAt')->set(new \DateTime())
        ->field('messages')->push($message)
        ->field('id')->equals(new \MongoId($conversationId))
        ->getQuery()
        ->execute();

    if ($flush) {
        $this->dm->flush();
    }
}
Run Code Online (Sandbox Code Playgroud)

我尝试的第二种方法是推送数组而不是对象:

public function reply($conversationId, Message $message)
{            
    $this->dm->createQueryBuilder($this->class)
        ->update()
        ->field('archivers')->unsetField()
        ->field('repliedBy')->set($message->getUserId())
        ->field('repliedBody')->set($message->getBody())
        ->field('repliedAt')->set(new \DateTime())
        ->field('modifiedAt')->set(new \DateTime())
        ->field('messages')->push(array(
            '_id' => new \MongoId(),
            'userId' => $message->getuserId(),
            'body' => $message->getBody(),
            'createdAt' => new \DateTime(),
            'modifiedAt' => new \DateTime(),
        ))
        ->field('id')->equals(new \MongoId($conversationId))
        ->getQuery() 
        ->execute();

    $this->dm->flush();
}
Run Code Online (Sandbox Code Playgroud)

哪个工作正常,直到调用flush()方法.flush()导致重复的对象被推送.所以我在对话中得到了同一个消息的两个副本(注释flush()解决了问题但是应用程序在其他类中有多个flush()调用).

另一个使用对象失败的推送查询:

public function archive($conversationId, $userId)
{

    $userStamp = new UserStamp();
    $userStamp->setUserId($userId);

    $this->dm->createQueryBuilder($this->class)
        ->update()
        ->field('archivers')->push($userStamp)
        ->field('modifiedAt')->set(new \DateTime())
        ->field('id')->equals(new \MongoId($conversationId))
        ->getQuery()
        ->execute();
}
Run Code Online (Sandbox Code Playgroud)

如果删除了push()调用,一切正常.

仍然停留在这一点上.

jmi*_*ola 3

查询生成器通常用于对 MongoDB 执行多文档或命令查询,从而绕过文档管理。唯一的例外是您正在执行水合查找查询,这在查询构建器文档中进行了描述。您上面的示例相当于:

$collection->update(
    ['_id' => new \MongoId($conversationId)],
    [
        '$set' => [
            'repliedBy' => $message->getUserId(),
            'repliedBody' => $message->getbody(),
            'repliedAt' => new \MongoDate(),
            'modifiedAt' => new \MongoDate(),
        ],
        '$push' => ['messages' => $message],
    ],
    ['multiple' => false]
);
Run Code Online (Sandbox Code Playgroud)

请注意,将使用您的字段映射(例如,Datetime 将成为 MongoDate),但没有可使用此查询管理的文档。