使用Doctrine ODM从mongodb文档中的数组中删除项


Remove item from array in a mongodb document using Doctrine ODM

我有一个mongoDB文档,包含以下结构:

{
        "_id" : ObjectId("537b9731fa4634134c8b45aa"),
        "kpis" : [
                {
                        "id" : 4,
                        "value" : 3.78,
                        "entered" : Timestamp(1401377656, 9)
                }
        ]
}

我想删除id为x的所有kpi文档。直接使用pull命令在数据库上执行此操作非常简单:

db.lead.update({}, {$pull:{"kpis":{id:5}}}, {multi:true});

然而,我(几次(尝试使用ODM理论来匹配这种语法都失败了:

    $qb->update()
       ->field('kpis')
       ->pull($qb->expr()->field('kpis.id')->equals($kpi->getId()))
       ->multiple(true)
       ->getQuery()
       ->execute();
    // I've also tried..
    $qb->update()
       ->field('kpis')
       ->pull($qb->expr()->field('kpis')->elemMatch(
            $qb->expr()->field('kpis.id')->equals($kpi->getId())
        ))
       ->multiple(true)
       ->getQuery()
       ->execute();

没有删除任何内容。我是否正确使用了查询生成器?

我相信你想做以下事情:

$qb->update()
    ->field('kpis')->pull(array('id' => $kpi->getId()))
    ->multiple(true)
    ->getQuery()
    ->execute();

您可以使用Query::debug()方法来转储由此生成的实际查询。您应该在转储的newObj字段中看到以下内容:

{ "$pull": { "kpis": { "id": <number> }}}

解释为什么你之前的例子不起作用:

->field('kpis')
->pull($qb->expr()->field('kpis.id')->equals($kpi->getId()))

在这里,您正在创建以下查询:

{ "$pull": { "kpis": { "kpis.id": <number> }}}

这只会匹配:

  1. 如果顶级kpis数组中的每个嵌入对象都有一个嵌入的kpis对象,而该对象又有一个与数字匹配的id字段
  2. 如果顶级kpis数组中的嵌入对象具有它们自己的kpis数组,该数组由具有匹配的id字段的嵌入对象组成。这将是MongoDB的数组元素匹配开始发挥作用

在第二个例子中,您有:

->field('kpis')
->pull($qb->expr()->field('kpis')->elemMatch(
    $qb->expr()->field('kpis.id')->equals($kpi->getId())
))

这将生成以下查询:

{ "$pull": { "kpis": { "$elemMatch": { "kpis.id": <number> }}}}

我以前从未见过这样的语法,但我认为$elemMatch非常出色,因为$pull已经将匹配数组元素的标准作为其参数。当您直接在数组字段上进行匹配,并且不想对数组元素进行完全相等匹配(即,您希望提供条件而不是精确匹配(时,$elemMatch在查询中很有用。