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

时间:2014-05-29 15:57:56

标签: php mongodb doctrine 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});

然而,我(几个)尝试使用doctrine 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();

什么都没有删除。我正确使用查询构建器吗?

1 个答案:

答案 0 :(得分:4)

我相信你想要做以下事情:

$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的array element matching开始发挥作用。
  3. 在你的第二个例子中,你有:

    ->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在查询中非常有用,并不意味着对数组元素进行完全相等匹配(即您想要提供标准而不是精确匹配)。