0

Shop多くがActivitiesとして定義されているドキュメントがある場合、インスタンスをハイドレートせずにforReferenceManyのリストを直接クエリできる方法はありますか?ActivitiesShopShop

例えば:

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

私が望むのは、「fd390j09afj09dfjactivities_idある配列を取得し、それらをインスタンスとして水和できる」と言えることだけです。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()
        ;

    }
4

1 に答える 1

1

Shop コレクションまたは (または ODM リポジトリ) を直接クエリして、Activity インスタンスを受け取ることはできません。ただし、クエリ ビルダ APIを使用して、 で射影を指定できますselect('activities')。実行されたクエリは引き続き Shop インスタンスを返しますが、activitiesハイドレートされるのはフィールドだけです (Activity インスタンスの PersistentCollection として)。この場合、ODM は null 以外の値を変更として検出するため、ハイドレートされていない Shop フィールドを変更しないでください。

select()上記のクエリを発行し、Shop の代わりに Activity ドキュメントのコレクション (または配列) を返す便利なメソッドを ShopRepository に追加するのは簡単です。ショップにアクセスできないようにしておくと、ショップ内の他の水和されていないフィールドを誤って変更することも防げます。

この方法の欠点は、Activity がプロキシ オブジェクトになり、遅延ロードされることです。これは、参照プライミングで軽減できます。プライミングを使用すると、最終的に 2 つのクエリを実行することになります (1 つは Shop 用、もう 1 つは参照されるすべてのアクティビティ ドキュメント用)。


このメソッドをアクティビティ リポジトリに配置することに関するフォローアップの質問については、別のオプションがあります。まず、ActivityRepository::findByShopId()Activity オブジェクトを返す ShopRepository でメソッドを呼び出すよりも好ましいことに同意します。

各リポジトリには、メソッドを介して他のリポジトリにアクセスするために使用できるドキュメント マネージャーへの参照がありますgetRepository()。次のActivityRepository::findByShopId()ことができます。

  • ドキュメント マネージャーを使用して Shop リポジトリにアクセスする
  • activitiesフィールドのみを投影し、ハイドレーションを完全に無効にして、その ID で Shop をクエリします。
  • activities配列から識別子を収集します。アクティビティ参照が単純かどうかに応じて、その配列の要素は生の_id値またはDBRefオブジェクトになります。
  • $inID が識別子の配列であるすべての Activity オブジェクトに対してクエリを実行します (既にそのリポジトリにいるので簡単です)。
于 2014-08-21T22:57:46.000 に答える