如何获取单个文档引用的所有文档?

时间:2014-08-21 05:54:17

标签: doctrine-mongodb

如果我的文档Shop有多个Activities定义为ReferenceMany,我是否有办法直接查询Activities的列表Shop 1}}没有保湿Shop实例?

例如:

{
    "_id": fd390j09afj09dfj,
    "activities": [
        ...
    ]
}

我想要的就是能够说'#34;给我activities _id fd390j09afj09dfj ,并将它们水合为Activity实例


这是我提出的第一个解决方案:

    /**
     * Gets all activities configured for a shop.
     *
     * @param string $shopId
     * @return \BikeShed\Domain\Activity[]|\Doctrine\Common\Collections\ArrayCollection
     */
    public function findByShopId($shopId) {

        /** @var \BikeShed\Domain\Repository\Shop $shopRepository */
        $shopRepository = $this->dm->getRepository('BikeShed\Domain\Shop');

        $shop = $shopRepository->findOneById($shopId);

        return $shop->getActivities();

    }

只需提取Shop,然后通过定义的关系获取所有Activities


以下是您如何实施jmikola最后建议的实例:

    /**
     * @param string $shopId
     * @return ActivityModel[]
     */
    public function findByShopId($shopId) {

        $partialShopData = $this->dm->getRepository('BikeShed\Domain\Shop')->createQueryBuilder()
            ->hydrate(false)
            ->field('activities')
            ->getQuery()
            ->getSingleResult()
        ;

        $activityIds = [];
        if(!empty($partialShopData['activities']))
            foreach($partialShopData['activities'] as $activity)
                if(!empty($activity['$id']))
                    $activityIds[] = $activity['$id'];

        return $this->createQueryBuilder()
            ->field('id')
            ->in($activityIds)
            ->getQuery()
            ->toArray()
        ;

    }

1 个答案:

答案 0 :(得分:1)

您不能直接查询Shop集合或(或ODM存储库)并接收Activity实例;但是,您可以使用Query Builder API指定select('activities')投影。执行的查询仍然会返回Shop实例,但activities字段应该是唯一的水合物(作为Activity实例的PersistentCollection)。在这种情况下,您不应修改任何非水合商店字段,因为ODM会将任何非空值视为更改。

在ShopRepository上添加一个方便的方法应该是微不足道的,该方法用select()发出上述查询并返回Activity文档的集合(或数组)而不是Shop。保持商店不可访问也应该保护您不会无意中修改其中的其他非水合田。

这种方法的缺点是活动将是代理对象并且延迟加载。您可以使用reference priming缓解此问题。启动后,您最终会执行两个查询(一个用于商店,一个用于所有引用的活动文档)。


关于将此方法放在Activity存储库上的后续问题,您还有其他选择。首先,我同意ActivityRepository::findByShopId()比在ShopRepository上调用返回Activity对象的方法更可取。

每个存储库都有对文档管理器的引用,您可以使用该引用通过getRepository()方法访问其他存储库。 ActivityRepository::findByShopId()可以执行以下操作:

  • 通过文档管理器访问Shop存储库
  • 按ID查询商店,仅投影activities字段并完全禁用水合作用
  • activities数组中收集标识符。根据Activity引用是否简单,该数组中的元素可能是原始_id值或DBRef对象。
  • 执行所有Activity对象的查询(很简单,因为我们已经在该存储库中),其中ID为$in标识符数组