我有一个引用用户的 Company 类:
/**
* @MongoDB\Document()
*/
class Company {
/* ... */
/**
* @MongoDB\ReferenceMany(targetDocument="Topboard\UserBundle\Document\User", inversedBy="companies")
*/
protected $users;
}
在我的控制器中,我需要检查公司中是否存在对用户的引用,并仅保留对该用户的引用,而不保留其他引用。我还想避免用户的多个数据库请求。我只是想检查参考文献的 id 是否匹配
$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;
}
经过调查发现,在初始化集合时会触发查询,以避免稍后对每个文档执行一个查询(原因是我们还不能做得更好,请参阅GH 上的此评论)。不过,情况并没有丢失,解决方案远非完美,但有时 OD/RM 在需要首先考虑性能时需要这些:
$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());
}
您也可以将逻辑放在我映射集合以获取引用用户的 id 列表的位置。
与单个引用或统一代理相关的原始答案
如果对象尚未加载(即它仍未初始化
Proxy
),那么询问该文档的标识符将不会触发额外的查询,这是我的项目中由ODM生成的Proxy
类的片段:
public function getId()
{
if ($this->__isInitialized__ === false) {
return parent::getId();
}
$this->__initializer__ && $this->__initializer__->__invoke($this, 'getId', []);
return parent::getId();
}
还要稍微扩展一下答案,您可以通过 priming 防止 n+1 问题,这样 ODM 将在一个查询中获取所有引用的文档。