Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Doctrine's MongoDB ODM - How do I find documents by embedded documents' fields?

I have the following Documents:

  • A User document.
  • An embedded document, containing a reference to (see next document)
  • a Site document

Each user has an array of embedded documents inside, each representing an item he follows - a site, a twitter account - with the option to mark specific categories he's interested in. Each embedded document has a reference to the third document - the Site document (or Twitter document, etc..).

The question is - using the MongoDB ODM, how can I get the documents of all the users that chose to follow a given site, using the id of that site ?
(see below (after the files) how it is done in the mongodb shell)

User.php

<?php
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ODM\Document
 */

class User {
    /**
     * @ODM\Id
     * @var string
     */
    protected $id;

    /**
     * @ODM\EmbedMany(
     *      discriminatorMap={
     *          "site"="SiteFollow",
     *          "twitter"="TwitterFollow",
     *      }
     *  )
     * @var ArrayCollection;
     */
    protected $follows;
}

SiteFollow.php

<?php
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ODM\EmbeddedDocument
 */

class SiteFollow {
    /**
     * @ODM\Collection
     * @var array
     */
    protected $interestingCategories;

    /**
     * @ODM\ReferenceOne(targetDocument="Site", simple=true)
     * @var Site
     */
    protected $siteItem;
}

Site.php

<?php
use Doctrine\ODM\MongoDB\Mapping\Annotations as ODM;

/**
 * @ODM\Document
 */

class Site {
    /**
     * @ODM\Id
     * @var string
     */
    protected $id;

    /**
     * @ODM\String
     * @var string
     */
    protected $name;

    /**
     * @ODM\String
     * @var string
     */
    protected $url;
}

An example for a user document in the mongo shell:

db.User.findOne()
{
    "_id": ObjectId("123"),
    "follows": [
        {
            "interestingCategories": [
                "PHP"
            ]
            "siteItem" : ObjectId("OBJECT_ID_OF_SITE_DOCUMENT"),
            "_doctrine_class_name" : "site"
        }
    ]
}

Mongo shell command for getting all the users that are following a specific site:

db.User.find({"follows.siteItem": ObjectId("OBJECT_ID_OF_SITE_DOCUMENT")})
like image 224
Doron Avatar asked Mar 06 '13 12:03

Doron


People also ask

Where can I find embedded files in MongoDB?

Accessing embedded/nested documents – In MongoDB, you can access the fields of nested/embedded documents of the collection using dot notation and when you are using dot notation, then the field and the nested field must be inside the quotation marks.

How would you query an array of embedded documents in MongoDB?

Use the Array Index to Query for a Field in the Embedded Document. Using dot notation, you can specify query conditions for field in a document at a particular index or position of the array. The array uses zero-based indexing. When querying using dot notation, the field and index must be inside quotation marks.

Why MongoDB uses embedded documents?

MongoDB provides you a cool feature which is known as Embedded or Nested Document. Embedded document or nested documents are those types of documents which contain a document inside another document.

What should we embed one document within another in MongoDB?

An embedded, or nested, MongoDB Document is a normal document that's nested inside another document within a MongoDB collection. Embedded documents are particularly useful when a one-to-many relationship exists between documents.


2 Answers

I found that answer provided by Madarco sometimes doesn't work properly. If you are querying for the $id field of the reference field in embedded document you may need to pass MongoId object to the equals() method. So in this case it would be:

$repo = $odm->getRepository('User');
$repo->createQueryBuilder()
    ->field('follows.siteItem.$id')
    ->equals(new \MongoId($siteId))
    ->getQuery()
    ->execute();
like image 158
sskorc Avatar answered Oct 05 '22 13:10

sskorc


Just query for the $id field of the DbRef field siteItem in the SiteFollow document (which is in an embedded collection in the User document):

$repo = $odm->getRepository("User");
$repo->createQueryBuilder()
         ->field("follows.siteItem.$id")
         ->equals($siteId)
         ->getQuery()
         ->execute();
like image 20
Madarco Avatar answered Oct 05 '22 13:10

Madarco