From a35d7d350c7b37f5f16296d6f1403c148ca046aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=B4me=20Tamarelle?= Date: Wed, 24 Jul 2024 16:30:18 +0200 Subject: [PATCH] Convert $near into $geoWithin for count --- CHANGELOG.md | 1 + src/Query/Builder.php | 20 +++++++++++++++++--- tests/QueryTest.php | 21 +++++++++++++++++++++ 3 files changed, 39 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4cffde726..c9ba5e592 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. * Add `Query\Builder::incrementEach()` and `decrementEach()` methods by @SmallRuralDog in [#2550](https://github.com/mongodb/laravel-mongodb/pull/2550) * Deprecate `Connection::collection()` and `Schema\Builder::collection()` methods by @GromNaN in [#3062](https://github.com/mongodb/laravel-mongodb/pull/3062) * Deprecate `Model::$collection` property to customize collection name. Use `$table` instead by @GromNaN in [#3064](https://github.com/mongodb/laravel-mongodb/pull/3064) +* Convert `$near` to `$geoWithin` in queries using aggregation by @GromNaN in [#3073](https://github.com/mongodb/laravel-mongodb/pull/3073) ## [4.7.0] - 2024-07-19 diff --git a/src/Query/Builder.php b/src/Query/Builder.php index ddc2413d8..27a40eb92 100644 --- a/src/Query/Builder.php +++ b/src/Query/Builder.php @@ -297,10 +297,9 @@ public function toMql(): array $columns = []; } - $wheres = $this->compileWheres(); - // Use MongoDB's aggregation framework when using grouping or aggregation functions. if ($this->groups || $this->aggregate) { + $wheres = $this->compileWheres(true); $group = []; $unwinds = []; @@ -404,6 +403,8 @@ public function toMql(): array return ['aggregate' => [$pipeline, $options]]; } + $wheres = $this->compileWheres(); + // Distinct query if ($this->distinct) { // Return distinct results directly @@ -414,6 +415,7 @@ public function toMql(): array return ['distinct' => [$column, $wheres, $options]]; } + // Normal query // Convert select columns to simple projections. $projection = array_fill_keys($columns, true); @@ -1133,7 +1135,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and' * * @return array */ - protected function compileWheres(): array + protected function compileWheres(bool $aggregation = false): array { // The wheres to compile. $wheres = $this->wheres ?: []; @@ -1150,6 +1152,18 @@ protected function compileWheres(): array if (isset($this->conversion[$where['operator']])) { $where['operator'] = $this->conversion[$where['operator']]; } + + // Convert $near to $geoWithin for aggregations + if ($aggregation && $where['operator'] === 'near' && isset($where['value']['$geometry']) && isset($where['value']['$maxDistance'])) { + $where['operator'] = 'geoWithin'; + $where['value'] = [ + '$centerSphere' => [ + $where['value']['$geometry']['coordinates'], + // Convert meters to radians + $where['value']['$maxDistance'] / 6378100, + ], + ]; + } } // Convert column name to string to use as array key diff --git a/tests/QueryTest.php b/tests/QueryTest.php index 2fd66bf70..71cb0b14f 100644 --- a/tests/QueryTest.php +++ b/tests/QueryTest.php @@ -574,6 +574,27 @@ public function testPaginateDistinct(): void User::distinct('age')->paginate(2); } + public function testPaginateNear(): void + { + User::insert([ + ['name' => 'Store A', 'position' => [9.224596977233887, 52.03082275390625]], + ['name' => 'Store B', 'position' => [9.224596977233887, 52.03082275390625]], + ['name' => 'Store C', 'position' => [9.3731451034548, 52.10194]], + ]); + + $query = User::where('position', 'near', [ + '$geometry' => [ + 'type' => 'Point', + 'coordinates' => [9.3731451034546, 52.1019308], + ], + '$maxDistance' => 50, + ]); + $result = $query->paginate(); // this results in error + + $this->assertCount(1, $result->items()); + $this->assertSame('Store C', $result->first()->name); + } + public function testUpdate(): void { $this->assertEquals(1, User::where(['name' => 'John Doe'])->update(['name' => 'Jim Morrison']));