From 15e30e75017f943b035e4193535d99b62ed0145f Mon Sep 17 00:00:00 2001 From: Philippe Gibert Date: Wed, 18 Feb 2015 17:49:37 +0100 Subject: [PATCH] Update aggregation builder Laravel 4.2 --- .gitignore | 2 + src/Jenssegers/Mongodb/Eloquent/Builder.php | 6 + src/Jenssegers/Mongodb/Query/Builder.php | 142 +++++++++++++++++--- 3 files changed, 134 insertions(+), 16 deletions(-) diff --git a/.gitignore b/.gitignore index a4a4579c3..409ae4e98 100644 --- a/.gitignore +++ b/.gitignore @@ -6,3 +6,5 @@ composer.lock *.sublime-project *.sublime-workspace *.project + +.idea \ No newline at end of file diff --git a/src/Jenssegers/Mongodb/Eloquent/Builder.php b/src/Jenssegers/Mongodb/Eloquent/Builder.php index 029617ff3..08423a95b 100644 --- a/src/Jenssegers/Mongodb/Eloquent/Builder.php +++ b/src/Jenssegers/Mongodb/Eloquent/Builder.php @@ -238,4 +238,10 @@ public function raw($expression = null) return $results; } + public function paginate($perPage = null, $columns = array('*')) { + + $this->query->addPaginateCols($columns); + return parent::paginate($perPage, $columns); + } + } diff --git a/src/Jenssegers/Mongodb/Query/Builder.php b/src/Jenssegers/Mongodb/Query/Builder.php index 92ebcbe21..b9149b7b6 100644 --- a/src/Jenssegers/Mongodb/Query/Builder.php +++ b/src/Jenssegers/Mongodb/Query/Builder.php @@ -33,6 +33,20 @@ class Builder extends QueryBuilder { */ public $timeout; + /** + * Flag for use aggregation + * + * @var bool + */ + protected $useAggregation = false; + + /** + * Paginate columns + * + * @var array + */ + protected $paginateCols = []; + /** * All of the available clause operators. * @@ -143,9 +157,11 @@ public function getFresh($columns = array()) $wheres = $this->compileWheres(); // Use MongoDB's aggregation framework when using grouping or aggregation functions. - if ($this->groups or $this->aggregate) + if ($this->groups or $this->aggregate or $this->useAggregation) { $group = array(); + $project = array(); + $projectEndColumns = array(); // Add grouping columns to the $group part of the aggregation pipeline. if ($this->groups) @@ -159,17 +175,12 @@ public function getFresh($columns = array()) $group[$column] = array('$last' => '$' . $column); } } - else - { - // If we don't use grouping, set the _id to null to prepare the pipeline for - // other aggregation functions. - $group['_id'] = null; - } // Add aggregation functions to the $group part of the aggregation pipeline, // these may override previous aggregations. if ($this->aggregate) { + $function = $this->aggregate['function']; foreach ($this->aggregate['columns'] as $column) @@ -187,25 +198,81 @@ public function getFresh($columns = array()) } } - // If no aggregation functions are used, we add the additional select columns - // to the pipeline here, aggregating them by $last. + else { + + // If no aggregation functions are used, we add the additional select columns + // to the pipeline here, aggregating them by $last. foreach ($this->columns as $column) { - $key = str_replace('.', '_', $column); + if (!in_array($column, $this->paginateCols) ) { + $key = str_replace('.', '_', $column); - $group[$key] = array('$last' => '$' . $column); + $group[$key] = array('$last' => '$' . $column); + } } + + + //add cols to filter groups and use mongoDb map/reduce + if ($this->columns) { + + if ($this->columns || $this->groups) { + $cols = array_merge((array)$this->columns, (array)$this->groups); + foreach ($cols as $column) { + $key = str_replace('.', '_', $column); + $project[$key] = 1; + } + } + + if ($this->columns) { + foreach ($cols as $column) { + $key = str_replace('.', '_', $column); + $projectEndColumns[$key] = 1; + } + } + } + } + // Build the aggregation pipeline. $pipeline = array(); if ($wheres) $pipeline[] = array('$match' => $wheres); - $pipeline[] = array('$group' => $group); + + + //filter used columns + if(!empty($project)) { + $pipeline[] = array('$project' => $project); + } + + if (!empty($group)) { + if (!isset($group['_id'])) { + // If we don't use grouping, set the _id to null to prepare the pipeline for + // other aggregation functions. + $group['_id'] = null; + } + + $pipeline[] = array('$group' => $group); + } + + //filter columns + if(!empty($projectEndColumns)) { + $pipeline[] = array('$project' => $projectEndColumns); + } + + + // Apply order and limit - if ($this->orders) $pipeline[] = array('$sort' => $this->orders); + if ($this->orders) { + if (isset($this->orders['$natural'])) { + unset($this->orders['$natural']); + } + if(!empty($this->orders)) { + $pipeline[] = array('$sort' => $this->orders); + } + } if ($this->offset) $pipeline[] = array('$skip' => $this->offset); if ($this->limit) $pipeline[] = array('$limit' => $this->limit); if ($this->projections) $pipeline[] = array('$project' => $this->projections); @@ -302,7 +369,6 @@ public function aggregate($function, $columns = array()) if (isset($results[0])) { $result = (array) $results[0]; - return $result['aggregate']; } } @@ -344,9 +410,54 @@ public function orderBy($column, $direction = 'asc') $this->orders[$column] = $direction; } + $this->useAggregation = true; + return $this; } + /** + * Set the "limit" value of the query. + * + * @param int $value + * @return $this + */ + public function limit($value) + { + $this->useAggregation = true; + + return parent::limit((int)$value); + } + + /** + * Set the "offset" value of the query. + * + * @param int $value + * @return $this + */ + public function offset($value) + { + $this->useAggregation = true; + + return parent::offset((int)$value); + } + + + public function paginate($perPage = 15, $columns = array('*')) { + + $this->addPaginateCols($columns); + return parent::paginate($perPage, $columns); + } + + public function addPaginateCols($columns) + { + if (in_array('*', $columns)) { + unset($columns[array_search('*', $columns)]); + } + $this->paginateCols = $this->paginateCols+$columns; + } + + + /** * Add a where between statement to the query. * @@ -716,12 +827,11 @@ public function convertKey($id) public function where($column, $operator = null, $value = null, $boolean = 'and') { $params = func_get_args(); - + // Remove the leading $ from operators. if (func_num_args() == 3) { $operator = &$params[1]; - if (starts_with($operator, '$')) { $operator = substr($operator, 1);