2016-06-29 2 views
1

У меня есть класс компании, ссылающиеся пользователи:Получить массив ссылочных идентификаторов в Doctrine ODM

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

    /* ... */ 

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

В моем контроллере мне нужно проверить, если ссылка на пользователь существует в компании и сохранить ссылку на этот пользователь, а не другие ссылки. Я также хочу избежать нескольких запросов БД для пользователей. Я просто хочу проверить, соответствует ли идентификатор ссылок $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; 

} 

ответ

1

При расследовании выяснилось, что запрос вызывается при инициализации коллекции, чтобы избежать одного запроса на документ позже (для рассуждений, почему мы не можем сделать еще лучше увидеть this comment on GH). Дело не теряется, хотя, решение не где-нибудь рядом быть красивой, но иногда OD/RMs требует их, когда производительность должна быть на первом месте:

$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()); 
} 

Вы также можете просто разместить свою логику в тех местах, где я картирование коллекции для получения списка идентификаторов пользователей, на которые делается ссылка.

Оригинальный ответ, который имеет важное значение для отдельных ссылок или unitinitailzed прокси

Если объект еще не загружен (т.е. еще не инициализирована Proxy), а затем просить идентификатора этого документа не вызовет дополнительных запросов, вот фрагмент кода из Proxy класса, порожденного ODM в моем проекте:

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


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

    return parent::getId(); 
} 

Кроме того, чтобы расширить ответ немного, вы можете предотвратить п + 1 проблема с priming, таким образом ODM будет получать все REFE в одном запросе.

+0

Прокси звучит о праве. Итак, вы предлагаете изменить идентификатор getter в классе User? Я думаю, проблема заключается в том, что когда я делаю 'foreach', он уже запускает запрос БД. – Websirnik

+0

Нет, ваш получатель должен оставаться неповрежденным, вы можете проверить autogenerated Proxy class (они обычно находятся в 'app/cache/lcl/doctrine/odm/mongodb/Proxies /'). Что касается 'foreach', он не должен инициировать запрос сам по себе, так как ваша ссылка - это собственная сторона, которая уже доступна в документе после начальной выборки. – malarzm

+0

Что я имею в виду, ваш код выглядит корректно и не должен запускать никаких дополнительных запросов в этот момент – malarzm

Смежные вопросы