3

I am having trouble in returning only the matched embedded document using MongoDB ODM query builder in PHP. Each embedded document has a MongoID generated at the time of creation. Following is my document structure of collection Project:

{ 
    "_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"
        }
    ]
}

Now i want to retrieve from the database only the class from the classes embedded documents which meets my criteria (i.e. class with a specific id).This is how i am building the query:

$qb = $dm->createQueryBuilder('Documents\Project');
$projectObj = $qb
    ->field('id')->equals("59f889e46803fa3713454b5d")
    ->field('classes')->elemMatch(
        $qb->expr()->field("id")->equals(new \MongoId("59f9d7776803faea30b895dd"))
    )
    ->hydrate(false)
    ->getQuery()
    ->getSingleResult();

First i match with the project id then i match with the embedded document class id. I was expecting it to return only the embedded document of OLA like this:

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

But doctrine is returning the whole Project record (shown in the start of question).I also tried with aggregation query building with the $match aggregation still the results are same the query i created with aggregation builder is as follows:

$qb = $dm->createAggregationBuilder('Documents\Project');
    $projectObj = $qb
        ->match()
        ->field('id')->equals($projectId)
        ->field('classes._id')->equals(new \MongoId($classId))
        ->execute()
        ->getSingleResult();

Can someone help me with regards to this issue? How can i build query that i get the desired result as mentioned above.

Seeker
  • 1,877
  • 4
  • 32
  • 56
  • 1
    ODM works with whole documents. Either filter it in the app, or use [aggregation](http://docs.doctrine-project.org/projects/doctrine-mongodb-odm/en/latest/reference/aggregation-builder.html). – Alex Blex Nov 01 '17 at 16:56
  • @AlexBlex i tried with that as well but still the results were same. I updated the question with the aggregation query builder – Seeker Nov 01 '17 at 17:05
  • 1
    You are using a single `match` stage which does exactly what the `find` does. You need at least a [project](https://docs.mongodb.com/manual/reference/operator/aggregation/project/#pipe._S_project) stage after that to re-shape the document. Look at [array functions](https://docs.mongodb.com/manual/meta/aggregation-quick-reference/#array-expressions) available there. – Alex Blex Nov 01 '17 at 17:33

1 Answers1

4

So after some trouble i am able to retrieve only the matched embedded document with the aggregation builder. So thanks to @Alex Bles comment i was able to think more on using aggregation functions and i found $filter array aggregation function and tried building query using that and the final query was like this:

    $qb = $dm->createAggregationBuilder('Documents\Project');
    $classObject = $qb->match()
       ->field("id", new \MongoId($projectId))
       ->project()
       ->field("classes")
       ->filter('$classes', 'class', $qb->expr()->eq('$$class._id', new \MongoId($classId)))
       ->execute()->getSingleResult();

So in the query first i matched with the _id of the project. then within that project i projected the results for the classes using the $filter array aggregation method. In the end i was able to get the embedded document filtered by their _id. Hope this will help someone in the future with same problem.

Seeker
  • 1,877
  • 4
  • 32
  • 56