From 039458d9db9fbd71617e8e5eaf907416853283a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fiete=20B=C3=B6rner?= Date: Wed, 10 Aug 2016 22:45:03 +0200 Subject: [PATCH 1/3] add sub document aggregation array functionality example: Model::sum('subarray.*.price'); this method is much simpler as to use as complex raw aggregations for this function a $unwind directive will be pushed in pipeline before $group --- src/Jenssegers/Mongodb/Query/Builder.php | 14 ++++++++++++++ tests/QueryBuilderTest.php | 16 ++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/Jenssegers/Mongodb/Query/Builder.php b/src/Jenssegers/Mongodb/Query/Builder.php index 74b9ee3a6..4aceeb421 100644 --- a/src/Jenssegers/Mongodb/Query/Builder.php +++ b/src/Jenssegers/Mongodb/Query/Builder.php @@ -187,6 +187,7 @@ public function getFresh($columns = []) // Use MongoDB's aggregation framework when using grouping or aggregation functions. if ($this->groups or $this->aggregate or $this->paginating) { $group = []; + $unwinds = []; // Add grouping columns to the $group part of the aggregation pipeline. if ($this->groups) { @@ -212,6 +213,13 @@ public function getFresh($columns = []) $function = $this->aggregate['function']; foreach ($this->aggregate['columns'] as $column) { + // Add unwind if a subdocument array should be aggregated + // column: subarray.price => {$unwind: '$subarray'} + if (count($splitColumns = explode('.*.', $column)) == 2) { + $unwinds[] = $splitColumns[0]; + $column = implode('.', $splitColumns); + } + // Translate count into sum. if ($function == 'count') { $group['aggregate'] = ['$sum' => 1]; @@ -241,6 +249,12 @@ public function getFresh($columns = []) if ($wheres) { $pipeline[] = ['$match' => $wheres]; } + + // apply unwinds for subdocument array aggregation + foreach($unwinds as $unwind){ + $pipeline[] = ['$unwind' => '$' . $unwind]; + } + if ($group) { $pipeline[] = ['$group' => $group]; } diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index ca08bf36a..6a3659cf4 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -419,6 +419,22 @@ public function testSubdocumentAggregate() $this->assertEquals(16.25, DB::collection('items')->avg('amount.hidden')); } + public function testSubdocumentArrayAggregate() + { + DB::collection('items')->insert([ + ['name' => 'knife', 'amount' => [['hidden' => 10, 'found' => 3]]], + ['name' => 'fork', 'amount' => [['hidden' => 35, 'found' => 12]]], + ['name' => 'spoon', 'amount' => [['hidden' => 14, 'found' => 21]]], + ['name' => 'spoon', 'amount' => [['hidden' => 6, 'found' => 4]]], + ]); + + $this->assertEquals(65, DB::collection('items')->sum('amount.*.hidden')); + $this->assertEquals(4, DB::collection('items')->count('amount.*.hidden')); + $this->assertEquals(6, DB::collection('items')->min('amount.*.hidden')); + $this->assertEquals(35, DB::collection('items')->max('amount.*.hidden')); + $this->assertEquals(16.25, DB::collection('items')->avg('amount.*.hidden')); + } + public function testUpsert() { DB::collection('items')->where('name', 'knife') From e615e53d6f329c795919c0da8da7df60997aa3c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fiete=20B=C3=B6rner?= Date: Sun, 14 Aug 2016 00:24:24 +0200 Subject: [PATCH 2/3] change testSubdocumentArrayAggregate change test for different scenarios --- tests/QueryBuilderTest.php | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tests/QueryBuilderTest.php b/tests/QueryBuilderTest.php index 6a3659cf4..9d45b17ba 100644 --- a/tests/QueryBuilderTest.php +++ b/tests/QueryBuilderTest.php @@ -422,17 +422,17 @@ public function testSubdocumentAggregate() public function testSubdocumentArrayAggregate() { DB::collection('items')->insert([ - ['name' => 'knife', 'amount' => [['hidden' => 10, 'found' => 3]]], - ['name' => 'fork', 'amount' => [['hidden' => 35, 'found' => 12]]], + ['name' => 'knife', 'amount' => [['hidden' => 10, 'found' => 3],['hidden' => 5, 'found' => 2]]], + ['name' => 'fork', 'amount' => [['hidden' => 35, 'found' => 12],['hidden' => 7, 'found' => 17],['hidden' => 1, 'found' => 19]]], ['name' => 'spoon', 'amount' => [['hidden' => 14, 'found' => 21]]], - ['name' => 'spoon', 'amount' => [['hidden' => 6, 'found' => 4]]], + ['name' => 'teaspoon', 'amount' => []], ]); - $this->assertEquals(65, DB::collection('items')->sum('amount.*.hidden')); - $this->assertEquals(4, DB::collection('items')->count('amount.*.hidden')); - $this->assertEquals(6, DB::collection('items')->min('amount.*.hidden')); + $this->assertEquals(72, DB::collection('items')->sum('amount.*.hidden')); + $this->assertEquals(6, DB::collection('items')->count('amount.*.hidden')); + $this->assertEquals(1, DB::collection('items')->min('amount.*.hidden')); $this->assertEquals(35, DB::collection('items')->max('amount.*.hidden')); - $this->assertEquals(16.25, DB::collection('items')->avg('amount.*.hidden')); + $this->assertEquals(12, DB::collection('items')->avg('amount.*.hidden')); } public function testUpsert() From 408d267629b88560297c4633e417057c4d72be27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Fiete=20B=C3=B6rner?= Date: Thu, 1 Sep 2016 11:17:03 +0200 Subject: [PATCH 3/3] rebase to latest master and fix style ci issues --- src/Jenssegers/Mongodb/Query/Builder.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Jenssegers/Mongodb/Query/Builder.php b/src/Jenssegers/Mongodb/Query/Builder.php index 4aceeb421..4bfc69986 100644 --- a/src/Jenssegers/Mongodb/Query/Builder.php +++ b/src/Jenssegers/Mongodb/Query/Builder.php @@ -251,7 +251,7 @@ public function getFresh($columns = []) } // apply unwinds for subdocument array aggregation - foreach($unwinds as $unwind){ + foreach ($unwinds as $unwind) { $pipeline[] = ['$unwind' => '$' . $unwind]; }