1717use ApiPlatform \Doctrine \Odm \PropertyHelperTrait as MongoDbOdmPropertyHelperTrait ;
1818use ApiPlatform \Metadata \Operation ;
1919use Doctrine \ODM \MongoDB \Aggregation \Builder ;
20+ use Doctrine \ODM \MongoDB \Aggregation \Stage \Search ;
2021use Doctrine \ODM \MongoDB \Aggregation \Stage \Sort ;
2122use Doctrine \Persistence \ManagerRegistry ;
2223
@@ -66,7 +67,8 @@ public function applyToCollection(Builder $aggregationBuilder, string $resourceC
6667 if ($ this ->isPropertyNested ($ field , $ resourceClass )) {
6768 [$ field ] = $ this ->addLookupsForNestedProperty ($ field , $ aggregationBuilder , $ resourceClass , true );
6869 }
69- $ aggregationBuilder ->sort (
70+ $ this ->addSort (
71+ $ aggregationBuilder ,
7072 $ context ['mongodb_odm_sort_fields ' ] = ($ context ['mongodb_odm_sort_fields ' ] ?? []) + [$ field => $ order ]
7173 );
7274 }
@@ -76,7 +78,8 @@ public function applyToCollection(Builder $aggregationBuilder, string $resourceC
7678
7779 if (null !== $ this ->order ) {
7880 foreach ($ identifiers as $ identifier ) {
79- $ aggregationBuilder ->sort (
81+ $ this ->addSort (
82+ $ aggregationBuilder ,
8083 $ context ['mongodb_odm_sort_fields ' ] = ($ context ['mongodb_odm_sort_fields ' ] ?? []) + [$ identifier => $ this ->order ]
8184 );
8285 }
@@ -88,26 +91,30 @@ protected function getManagerRegistry(): ManagerRegistry
8891 return $ this ->managerRegistry ;
8992 }
9093
91- private function hasSortStage (Builder $ aggregationBuilder ): bool
94+ private function addSort (Builder $ aggregationBuilder, array $ sortFields ): void
9295 {
93- $ shouldStop = false ;
94- $ index = 0 ;
96+ $ firstStage = $ aggregationBuilder ->getPipeline (0 );
97+ if ($ firstStage instanceof Search) {
98+ // The $search stage supports "sort" for performance, it's always first if present
99+ $ firstStage ->sort ($ sortFields );
100+ } else {
101+ // Append a $sort stage at the end of the pipeline
102+ $ aggregationBuilder ->sort ($ sortFields );
103+ }
104+ }
95105
96- do {
97- try {
106+ private function hasSortStage (Builder $ aggregationBuilder ): bool
107+ {
108+ try {
109+ for ($ index = 0 ; true ; $ index ++) {
98110 if ($ aggregationBuilder ->getStage ($ index ) instanceof Sort) {
99111 // If at least one stage is sort, then it has sorting
100112 return true ;
101113 }
102- } catch (\OutOfRangeException $ outOfRangeException ) {
103- // There is no more stages on the aggregation builder
104- $ shouldStop = true ;
105114 }
106-
107- ++$ index ;
108- } while (!$ shouldStop );
109-
110- // No stage was sort, and we iterated through all stages
111- return false ;
115+ } catch (\OutOfRangeException ) {
116+ // There is no more stages on the aggregation builder
117+ return false ;
118+ }
112119 }
113120}
0 commit comments