@@ -7864,7 +7864,7 @@ public function find(string $collection, array $queries = [], string $forPermiss
78647864 $ nestedSelections = $ this ->processRelationshipQueries ($ relationships , $ queries );
78657865
78667866 // Convert relationship filter queries to SQL-level subqueries
7867- $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries );
7867+ $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries, $ collection );
78687868
78697869 // If conversion returns null, it means no documents can match (relationship filter found no matches)
78707870 if ($ queriesOrNull === null ) {
@@ -8064,7 +8064,7 @@ public function count(string $collection, array $queries = [], ?int $max = null)
80648064 $ queries = Query::groupByType ($ queries )['filters ' ];
80658065 $ queries = $ this ->convertQueries ($ collection , $ queries );
80668066
8067- $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries );
8067+ $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries, $ collection );
80688068
80698069 if ($ queriesOrNull === null ) {
80708070 return 0 ;
@@ -8130,7 +8130,7 @@ public function sum(string $collection, string $attribute, array $queries = [],
81308130 );
81318131
81328132 $ queries = $ this ->convertQueries ($ collection , $ queries );
8133- $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries );
8133+ $ queriesOrNull = $ this ->convertRelationshipQueries ($ relationships , $ queries, $ collection );
81348134
81358135 // If conversion returns null, it means no documents can match (relationship filter found no matches)
81368136 if ($ queriesOrNull === null ) {
@@ -9084,6 +9084,7 @@ private function processNestedRelationshipPath(string $startCollection, array $q
90849084 private function convertRelationshipQueries (
90859085 array $ relationships ,
90869086 array $ queries ,
9087+ ?Document $ collection = null ,
90879088 ): ?array {
90889089 // Early return if no relationship queries exist
90899090 $ hasRelationshipQuery = false ;
@@ -9134,7 +9135,7 @@ private function convertRelationshipQueries(
91349135 $ resolvedAttribute = '$id ' ;
91359136 foreach ($ query ->getValues () as $ value ) {
91369137 $ relatedQuery = Query::equal ($ nestedAttribute , [$ value ]);
9137- $ result = $ this ->resolveRelationshipGroupToIds ($ relationship , [$ relatedQuery ]);
9138+ $ result = $ this ->resolveRelationshipGroupToIds ($ relationship , [$ relatedQuery ], $ collection );
91389139
91399140 if ($ result === null ) {
91409141 return null ;
@@ -9220,7 +9221,7 @@ private function convertRelationshipQueries(
92209221 }
92219222
92229223 try {
9223- $ result = $ this ->resolveRelationshipGroupToIds ($ relationship , $ relatedQueries );
9224+ $ result = $ this ->resolveRelationshipGroupToIds ($ relationship , $ relatedQueries, $ collection );
92249225
92259226 if ($ result === null ) {
92269227 return null ;
@@ -9252,11 +9253,13 @@ private function convertRelationshipQueries(
92529253 *
92539254 * @param Document $relationship
92549255 * @param array<Query> $relatedQueries Queries on the related collection
9256+ * @param Document|null $collection The parent collection document (needed for junction table lookups)
92559257 * @return array{attribute: string, ids: string[]}|null
92569258 */
92579259 private function resolveRelationshipGroupToIds (
92589260 Document $ relationship ,
92599261 array $ relatedQueries ,
9262+ ?Document $ collection = null ,
92609263 ): ?array {
92619264 $ relatedCollection = $ relationship ->getAttribute ('options ' )['relatedCollection ' ];
92629265 $ relationType = $ relationship ->getAttribute ('options ' )['relationType ' ];
@@ -9294,24 +9297,52 @@ private function resolveRelationshipGroupToIds(
92949297 ($ relationType === self ::RELATION_MANY_TO_MANY )
92959298 );
92969299
9297- if ($ needsParentResolution ) {
9298- $ matchingDocs = $ this ->silent (fn () => $ this ->find (
9300+ if ($ relationType === self ::RELATION_MANY_TO_MANY && $ needsParentResolution && $ collection !== null ) {
9301+ // For many-to-many, query the junction table directly instead of relying
9302+ // on relationship population (which fails when resolveRelationships is false,
9303+ // e.g. when the outer find() is wrapped in skipRelationships()).
9304+ $ matchingDocs = $ this ->silent (fn () => $ this ->skipRelationships (fn () => $ this ->find (
92999305 $ relatedCollection ,
93009306 \array_merge ($ relatedQueries , [
9307+ Query::select (['$id ' ]),
93019308 Query::limit (PHP_INT_MAX ),
93029309 ])
9303- ));
9304- } else {
9305- $ matchingDocs = $ this ->silent (fn () => $ this ->skipRelationships (fn () => $ this ->find (
9310+ )));
9311+
9312+ $ matchingIds = \array_map (fn ($ doc ) => $ doc ->getId (), $ matchingDocs );
9313+
9314+ if (empty ($ matchingIds )) {
9315+ return null ;
9316+ }
9317+
9318+ $ twoWayKey = $ relationship ->getAttribute ('options ' )['twoWayKey ' ];
9319+ $ relatedCollectionDoc = $ this ->silent (fn () => $ this ->getCollection ($ relatedCollection ));
9320+ $ junction = $ this ->getJunctionCollection ($ collection , $ relatedCollectionDoc , $ side );
9321+
9322+ $ junctionDocs = $ this ->silent (fn () => $ this ->skipRelationships (fn () => $ this ->find ($ junction , [
9323+ Query::equal ($ relationshipKey , $ matchingIds ),
9324+ Query::limit (PHP_INT_MAX ),
9325+ ])));
9326+
9327+ $ parentIds = [];
9328+ foreach ($ junctionDocs as $ jDoc ) {
9329+ $ pId = $ jDoc ->getAttribute ($ twoWayKey );
9330+ if ($ pId && !\in_array ($ pId , $ parentIds )) {
9331+ $ parentIds [] = $ pId ;
9332+ }
9333+ }
9334+
9335+ return empty ($ parentIds ) ? null : ['attribute ' => '$id ' , 'ids ' => $ parentIds ];
9336+ } elseif ($ needsParentResolution ) {
9337+ // For one-to-many/many-to-one parent resolution, we need relationship
9338+ // population to read the twoWayKey attribute from the related documents.
9339+ $ matchingDocs = $ this ->silent (fn () => $ this ->find (
93069340 $ relatedCollection ,
93079341 \array_merge ($ relatedQueries , [
9308- Query::select (['$id ' ]),
93099342 Query::limit (PHP_INT_MAX ),
93109343 ])
9311- )));
9312- }
9344+ ));
93139345
9314- if ($ needsParentResolution ) {
93159346 $ twoWayKey = $ relationship ->getAttribute ('options ' )['twoWayKey ' ];
93169347 $ parentIds = [];
93179348
@@ -9339,6 +9370,14 @@ private function resolveRelationshipGroupToIds(
93399370
93409371 return empty ($ parentIds ) ? null : ['attribute ' => '$id ' , 'ids ' => $ parentIds ];
93419372 } else {
9373+ $ matchingDocs = $ this ->silent (fn () => $ this ->skipRelationships (fn () => $ this ->find (
9374+ $ relatedCollection ,
9375+ \array_merge ($ relatedQueries , [
9376+ Query::select (['$id ' ]),
9377+ Query::limit (PHP_INT_MAX ),
9378+ ])
9379+ )));
9380+
93429381 $ matchingIds = \array_map (fn ($ doc ) => $ doc ->getId (), $ matchingDocs );
93439382 return empty ($ matchingIds ) ? null : ['attribute ' => $ relationshipKey , 'ids ' => $ matchingIds ];
93449383 }
0 commit comments