Skip to content

Commit 7082063

Browse files
author
Fiete Börner
committed
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
1 parent e1c12ac commit 7082063

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/Jenssegers/Mongodb/Query/Builder.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -179,6 +179,7 @@ public function getFresh($columns = [])
179179
// Use MongoDB's aggregation framework when using grouping or aggregation functions.
180180
if ($this->groups or $this->aggregate or $this->paginating) {
181181
$group = [];
182+
$unwinds = [];
182183

183184
// Add grouping columns to the $group part of the aggregation pipeline.
184185
if ($this->groups) {
@@ -204,6 +205,13 @@ public function getFresh($columns = [])
204205
$function = $this->aggregate['function'];
205206

206207
foreach ($this->aggregate['columns'] as $column) {
208+
// Add unwind if a subdocument array should be aggregated
209+
// column: subarray.price => {$unwind: '$subarray'}
210+
if (count($splitColumns = explode('.*.', $column)) == 2) {
211+
$unwinds[] = $splitColumns[0];
212+
$column = implode('.', $splitColumns);
213+
}
214+
207215
// Translate count into sum.
208216
if ($function == 'count') {
209217
$group['aggregate'] = ['$sum' => 1];
@@ -233,6 +241,12 @@ public function getFresh($columns = [])
233241
if ($wheres) {
234242
$pipeline[] = ['$match' => $wheres];
235243
}
244+
245+
// apply unwinds for subdocument array aggregation
246+
foreach($unwinds as $unwind){
247+
$pipeline[] = ['$unwind' => '$' . $unwind];
248+
}
249+
236250
if ($group) {
237251
$pipeline[] = ['$group' => $group];
238252
}

tests/QueryBuilderTest.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,22 @@ public function testSubdocumentAggregate()
420420
$this->assertEquals(16.25, DB::collection('items')->avg('amount.hidden'));
421421
}
422422

423+
public function testSubdocumentArrayAggregate()
424+
{
425+
DB::collection('items')->insert([
426+
['name' => 'knife', 'amount' => [['hidden' => 10, 'found' => 3]]],
427+
['name' => 'fork', 'amount' => [['hidden' => 35, 'found' => 12]]],
428+
['name' => 'spoon', 'amount' => [['hidden' => 14, 'found' => 21]]],
429+
['name' => 'spoon', 'amount' => [['hidden' => 6, 'found' => 4]]],
430+
]);
431+
432+
$this->assertEquals(65, DB::collection('items')->sum('amount.*.hidden'));
433+
$this->assertEquals(4, DB::collection('items')->count('amount.*.hidden'));
434+
$this->assertEquals(6, DB::collection('items')->min('amount.*.hidden'));
435+
$this->assertEquals(35, DB::collection('items')->max('amount.*.hidden'));
436+
$this->assertEquals(16.25, DB::collection('items')->avg('amount.*.hidden'));
437+
}
438+
423439
public function testUpsert()
424440
{
425441
DB::collection('items')->where('name', 'knife')

0 commit comments

Comments
 (0)