Doctrine ODM(mongo) - upsert嵌入文档(如果不存在)

时间:2016-04-13 08:20:30

标签: mongodb doctrine-orm doctrine-odm

存在连接用户和汽车的mongo文档。它包含以下字段:

  • User.userId
  • User.cars []
  • User.updated
  • User.created

User.cars是嵌入式文档的数组。如果查询尚未包含ID为$ carId的Car

,则需要编写查询以仅将Car插入此字段

以下查询将每次为$ userId和$ carId创建一条新记录。它应该做的是不插入新记录或更新驱动值。

    $qb
        ->findAndUpdate()
        ->upsert(true)
        ->field('userId')->equals($userId)
        ->field('cars.id')->notEqual($carId)
        ->field('cars')->addToSet([
                'id' => $carId,
                'driven' => new \DateTime(),
        ])
        ->field('updated')->set(new \DateTime())
        ->field('created')->setOnInsert(new \DateTime())
        ->limit(1)
    ;
    return $qb->getQuery()->execute();

从查询中删除notEqual($ carId)将始终将记录插入User.cars,这也是不可取的。

最终结果应该是User.cars只包含每个carId的一条记录。

1 个答案:

答案 0 :(得分:0)

如果您以后不需要搜索cars数组,则可以将其存储为对象,并使用$carId作为关键字:

$qb
    ->findAndUpdate()
    ->upsert(true)
    ->field('userId')->equals($userId)
    ->field("cars.$carId")->set([
            'id' => $carId,
            'driven' => new \DateTime(),
    ])
    ->field('updated')->set(new \DateTime())
    ->field('created')->setOnInsert(new \DateTime())
    ->limit(1)
;
return $qb->getQuery()->execute();

如果cars在文档中映射为EmbedMany,您可能需要将collection's strategy更改为setatomicSet(我建议后者)否则ODM会在每次保存时重新索引数组。

再一次,这个解决方案有其缺点,根据您希望如何使用您的数据,它可以被认为是严重的,但它解决了有问题的问题。

另外,->limit(1)是多余的,因为->findAndUpdate()正在进行查询运行findAndModify命令,该命令本质上是针对单个文档运行的。