PHPMongo - 在MongoDB中仅查找并返回匹配的嵌入式文档

时间:2017-11-08 14:42:22

标签: php mongodb php-mongodb

我在使用sokil PHPMongo ODM库返回匹配的嵌入式文档时遇到问题。我是ODM概念的新手,以下是我的文档结构项目:

{ 
    "_id" : ObjectId("59f889e46803fa3713454b5d"), 
    "projectName" : "usecase-updated", 
    "classes" : [
        {
            "_id" : ObjectId("59f9d7776803faea30b895dd"), 
            "className" : "OLA"
        }, 
        {
            "_id" : ObjectId("59f9d8ad6803fa4012b895df"), 
            "className" : "HELP"
        }, 
        {
            "_id" : ObjectId("59f9d9086803fa4112b895de"), 
            "className" : "DOC"
        }, 
        {
            "_id" : ObjectId("59f9d9186803fa4212b895de"), 
            "className" : "INVOC"
        }
    ]
}

因此,在我的查询中,第一个标准是使用匹配的ID获取项目,第二个条件是仅从具有特定id的嵌入文档的classes数组中检索类。这就是我如何构建查询:

$collection = $PHPMongoDBInstance->getCollection("Project");



  $result = $collection->getDocument(
    "59f889e46803fa3713454b5d",
    function (\Sokil\Mongo\Cursor $cursor) {
        // get embedded documents with matched id
        $cursor->whereElemMatch("classes", $cursor->expression()->where("_id", new MongoId("59f9d7776803faea30b895dd")));

    }
);

我希望它只返回OLA文档中usecase-updated的嵌入文档,如下所示:

{ 
   "_id" : ObjectId("59f889e46803fa3713454b5d"), 
    "projectName" : "usecase-updated", 
    "classes" : [
          {
            "_id" : ObjectId("59f9d7776803faea30b895dd"), 
            "className" : "OLA"
          }
     ]
}

但是PHPMongo库正在返回所有类的整个项目文档(在问题的开头显示)。有人建议调查聚合框架。但问题是PHPMongo上有关于使用数组聚合函数(如$filter

的文档不够好

我是通过使用MongoCollection的原生实例尝试的,我可以使用findOne方法以这种方式投影我的最终结果:

$result = $collection->getMongoCollection("Project")->
             findOne(array("_id" => new MongoId("59f889e46803fa3713454b5d")), 
             array("classes" => 
                    array('$elemMatch' => 
                           array("_id" => new MongoId("59f9d7776803faea30b895dd")))));

如果我想使用sokil PHPMongogetDocument方法实现类似投影,是否有可能?

更新 我尝试使用聚合框架实现,以下是查询:

$result = $collection->aggregate(array(
    array(
        '$match' => array(
            "_id" => new MongoId("59f889e46803fa3713454b5d")
        )
    ),
    array(
        '$project' => array(
            'classes' => array(
                '$filter' => array(
                    'input' => '$classes',
                    'as' => 'classItem',
                    'cond' => array(
                        '$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))
                    )
                )

            )

        )
    )

));

但我得到了这个例外:

Sokil\\Mongo\\Exception\nMessage: Aggregate error: Unrecognized expression '$$classItem._id'\nFile:

1 个答案:

答案 0 :(得分:0)

因此posting问题发生在PHPMongo GitHub问题之后,我发现到目前为止还没有实现$elemMatch。作者在这个问题上发布了一些interesting insights,现在这个问题被标记为未来的增强。

此外,我已经尝试了聚合框架,并且我成功地能够达到预期的结果,我发现下面的表达式的语法中存在错误(对于完整查询,请参阅上面的问题):

'$eq' => array('$$classItem._id' => new MongoId("59f9d7776803faea30b895dd"))

我了解到'$eq'的表达式不应该是关联数组,而表达式中的每个元素都应该是一个单独的数组项,如下所示:

'$eq' => array('$$class._id', new MongoId("59f9d7776803faea30b895dd"))

所以现在我的最终聚合查询是这样的:

$collection = $PHPMongoDBInstance->getCollection("Project");
$result = $collection->aggregate(array(
    array(
        '$match' => array(
            "_id" => new MongoId('59f889e46803fa3713454b5d')
        )
    ),
    array(
        '$project' => array(
            'classes' => array(
                '$filter' => array(
                    'input' => '$classes',
                    'as' => 'class',
                    'cond' => array(
                        '$eq' => array('$$class._id', new MongoId("59f9d7776803faea30b895dd"))
                    )
                )
            ),
            'projectName' => 1
        )
    )
));

希望这将有助于未来的人,如果他们遇到类似我的问题,因为我试图找到解决方案而且它不在互联网上。一旦$elemMatch的PHPMongo中有功能增强,我将尝试更新。