Websirnik
Websirnik

Reputation: 1412

Get array of referenced ids in Doctrine ODM

I have a Company class that references users:

/**
 * @MongoDB\Document()
 */
class Company {

    /* ... */

    /**
     * @MongoDB\ReferenceMany(targetDocument="Topboard\UserBundle\Document\User", inversedBy="companies")
     */
    protected $users;
}

In my controller I need to check if the reference to the user exists in the company and keep only the reference to that user, not other references. I also want to avoid multiple DB requests for users. I just want to check if the id of the references matches $currentUserId.

public function getCompanyAction($companyId, $currentUserId) {
    $dm = $this->get('doctrine_mongodb')->getManager();
    $company = $dm->getRepository( 'TopboardAppBundle:Company' )->findOneById( $companyId );

    foreach ($company->getUsers() as $user) {
        // Foreach will query each user separetly. This is not what I need.
        // I need somehow access array of references' ids
        // and compare them with the $currentUserId
        if($user->getId() !== $currentUserId){
            // Remove reference
        }        
    }

    return $company;

}

Upvotes: 1

Views: 1238

Answers (1)

malarzm
malarzm

Reputation: 2966

Upon investigation it turned out that the query is fired when collection is initialized to avoid one query per document later (for reasoning why we can't do better yet see this comment on GH). The case is not lost though, solution is not anywhere near being beautiful, but sometimes OD/RMs requires these when performance needs to come first:

$users = $company->getUsers();
// condition below assumes $company is loaded from db so $users is in fact instance of PersistentCollection(Interface)
if ($users->isInitialized()) {
   $ids = $users->map(function($user) { 
       return $user->getId(); 
   })->toArray();
} else {
   $ids = array_map(function($dbRef) { 
        /* this depends on reference type */ 
        return (string) $dbRef['$id']; 
   }, $users->getMongoData());
}

You could also just place your logic in places where I'm mapping collections to get list of ids of referenced users.

Original answer that is relevant for single references or unitinitailzed proxies

If object is not loaded yet (i.e. it is still uninitialized Proxy) then asking for that document's identifier will not trigger additional queries, here is snippet of a Proxy class generated by ODM in my project:

public function getId()
{
    if ($this->__isInitialized__ === false) {
        return  parent::getId();
    }


    $this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);

    return parent::getId();
}

Also to expand answer a bit, you can prevent n+1 problem with priming, this way ODM will fetch all referenced documents in one query.

Upvotes: 1

Related Questions