Skip to content
This repository has been archived by the owner on Nov 11, 2020. It is now read-only.

Commit

Permalink
Merge pull request #292 from alcaeus/new-aggregation-pipelines
Browse files Browse the repository at this point in the history
Add support for aggregation pipeline stages added in MongoDB 3.4
  • Loading branch information
alcaeus committed Jun 22, 2017
2 parents 908225c + 04826ef commit 1334741
Show file tree
Hide file tree
Showing 27 changed files with 2,041 additions and 23 deletions.
114 changes: 114 additions & 0 deletions lib/Doctrine/MongoDB/Aggregation/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,59 @@ public function addFields()
return $this->addStage(new Stage\AddFields($this));
}

/**
* Categorizes incoming documents into groups, called buckets, based on a
* specified expression and bucket boundaries.
*
* Each bucket is represented as a document in the output. The document for
* each bucket contains an _id field, whose value specifies the inclusive
* lower bound of the bucket and a count field that contains the number of
* documents in the bucket. The count field is included by default when the
* output is not specified.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/bucket/
*
* @return Stage\Bucket
*/
public function bucket()
{
return $this->addStage(new Stage\Bucket($this));
}

/**
* Categorizes incoming documents into a specific number of groups, called
* buckets, based on a specified expression.
*
* Bucket boundaries are automatically determined in an attempt to evenly
* distribute the documents into the specified number of buckets. Each
* bucket is represented as a document in the output. The document for each
* bucket contains an _id field, whose value specifies the inclusive lower
* bound and the exclusive upper bound for the bucket, and a count field
* that contains the number of documents in the bucket. The count field is
* included by default when the output is not specified.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/
*
* @return Stage\BucketAuto
*/
public function bucketAuto()
{
return $this->addStage(new Stage\BucketAuto($this));
}

/**
* Returns a document that contains a count of the number of documents input
* to the stage.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/count/
*
* @return Stage\Count
*/
public function count($fieldName)
{
return $this->addStage(new Stage\Count($this, $fieldName));
}

/**
* @return Expr
*/
Expand All @@ -93,6 +146,20 @@ public function execute($options = [])
return $this->collection->aggregate($this->getPipeline(), $options);
}

/**
* Processes multiple aggregation pipelines within a single stage on the
* same set of input documents.
*
* Each sub-pipeline has its own field in the output document where its
* results are stored as an array of documents.
*
* @return Stage\Facet
*/
public function facet()
{
return $this->addStage(new Stage\Facet($this));
}

/**
* Outputs documents in order of nearest to farthest from a specified point.
*
Expand Down Expand Up @@ -142,6 +209,21 @@ function (Stage $stage) { return $stage->getExpression(); },
);
}

/**
* Performs a recursive search on a collection, with options for restricting
* the search by recursion depth and query filter.
*
* @see https://docs.mongodb.org/manual/reference/operator/aggregation/graphLookup/
*
* @param string $from Target collection for the $graphLookup operation to
* search, recursively matching the connectFromField to the connectToField.
* @return Stage\GraphLookup
*/
public function graphLookup($from)
{
return $this->addStage(new Stage\GraphLookup($this, $from));
}

/**
* Groups documents by some specified expression and outputs to the next
* stage a document for each distinct grouping.
Expand Down Expand Up @@ -259,6 +341,24 @@ public function redact()
return $this->addStage(new Stage\Redact($this));
}

/**
* Promotes a specified document to the top level and replaces all other
* fields.
*
* The operation replaces all existing fields in the input document,
* including the _id field. You can promote an existing embedded document to
* the top level, or create a new document for promotion.
*
* @param string|null $expression Optional. A replacement expression that
* resolves to a document.
*
* @return Stage\ReplaceRoot
*/
public function replaceRoot($expression = null)
{
return $this->addStage(new Stage\ReplaceRoot($this, $expression));
}

/**
* Randomly selects the specified number of documents from its input.
*
Expand Down Expand Up @@ -304,6 +404,20 @@ public function sort($fieldName, $order = null)
return $this->addStage(new Stage\Sort($this, $fieldName, $order));
}

/**
* Groups incoming documents based on the value of a specified expression,
* then computes the count of documents in each distinct group.
*
* @see http://docs.mongodb.org/manual/reference/operator/aggregation/sortByCount/
*
* @param string $expression The expression to group by
* @return Stage\SortByCount
*/
public function sortByCount($expression)
{
return $this->addStage(new Stage\SortByCount($this, $expression));
}

/**
* Deconstructs an array field from the input documents to output a document
* for each element. Each output document is the input document with the
Expand Down
41 changes: 27 additions & 14 deletions lib/Doctrine/MongoDB/Aggregation/Expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ public function addAnd($expression /*, $expression2, ... */)
$this->expr['$and'] = [];
}

$this->expr['$and'] = array_merge($this->expr['$and'], array_map([$this, 'ensureArray'], func_get_args()));
$this->expr['$and'] = array_merge($this->expr['$and'], array_map(['static', 'convertExpression'], func_get_args()));

return $this;
}
Expand All @@ -108,7 +108,7 @@ public function addOr($expression /*, $expression2, ... */)
$this->expr['$or'] = [];
}

$this->expr['$or'] = array_merge($this->expr['$or'], array_map([$this, 'ensureArray'], func_get_args()));
$this->expr['$or'] = array_merge($this->expr['$or'], array_map(['static', 'convertExpression'], func_get_args()));

return $this;
}
Expand Down Expand Up @@ -281,27 +281,40 @@ public function cond($if, $then, $else)
}

/**
* Ensures an array or operator expression is converted to an array.
* Converts an expression object into an array, recursing into nested items
*
* For expression objects, it calls getExpression on the expression object.
* For arrays, it recursively calls itself for each array item. Other values
* are returned directly.
*
* @param mixed|self $expression
* @return mixed
* @return string|array
* @internal
*/
protected function ensureArray($expression)
public static function convertExpression($expression)
{
if (is_array($expression)) {
$array = [];
foreach ($expression as $index => $value) {
$array[$index] = $this->ensureArray($value);
}

return $array;
return array_map(['static', 'convertExpression'], $expression);
} elseif ($expression instanceof self) {
return $expression->getExpression();
}

return $expression;
}

/**
* Ensures an array or operator expression is converted to an array.
*
* @deprecated Deprecated in favor of convertExpression
*
* @param mixed|self $expression
* @return mixed
*/
protected function ensureArray($expression)
{
return static::convertExpression($expression);
}

/**
* Converts a date object to a string according to a user-specified format.
*
Expand Down Expand Up @@ -430,7 +443,7 @@ public function expr()
public function expression($value)
{
$this->requiresCurrentField(__METHOD__);
$this->expr[$this->currentField] = $this->ensureArray($value);
$this->expr[$this->currentField] = static::convertExpression($value);

return $this;
}
Expand Down Expand Up @@ -881,9 +894,9 @@ public function not($expression)
private function operator($operator, $expression)
{
if ($this->currentField) {
$this->expr[$this->currentField][$operator] = $this->ensureArray($expression);
$this->expr[$this->currentField][$operator] = static::convertExpression($expression);
} else {
$this->expr[$operator] = $this->ensureArray($expression);
$this->expr[$operator] = static::convertExpression($expression);
}

return $this;
Expand Down
114 changes: 114 additions & 0 deletions lib/Doctrine/MongoDB/Aggregation/Stage.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,73 @@ public function execute($options = [])
return $this->builder->execute($options);
}

/**
* Categorizes incoming documents into groups, called buckets, based on a
* specified expression and bucket boundaries.
*
* Each bucket is represented as a document in the output. The document for
* each bucket contains an _id field, whose value specifies the inclusive
* lower bound of the bucket and a count field that contains the number of
* documents in the bucket. The count field is included by default when the
* output is not specified.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/bucket/
*
* @return Stage\Bucket
*/
public function bucket()
{
return $this->builder->bucket();
}

/**
* Categorizes incoming documents into a specific number of groups, called
* buckets, based on a specified expression.
*
* Bucket boundaries are automatically determined in an attempt to evenly
* distribute the documents into the specified number of buckets. Each
* bucket is represented as a document in the output. The document for each
* bucket contains an _id field, whose value specifies the inclusive lower
* bound and the exclusive upper bound for the bucket, and a count field
* that contains the number of documents in the bucket. The count field is
* included by default when the output is not specified.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/bucketAuto/
*
* @return Stage\BucketAuto
*/
public function bucketAuto()
{
return $this->builder->bucketAuto();
}

/**
* Returns a document that contains a count of the number of documents input
* to the stage.
*
* @see https://docs.mongodb.com/manual/reference/operator/aggregation/count/
*
* @return Stage\Count
*/
public function count($fieldName)
{
return $this->builder->count($fieldName);
}

/**
* Processes multiple aggregation pipelines within a single stage on the
* same set of input documents.
*
* Each sub-pipeline has its own field in the output document where its
* results are stored as an array of documents.
*
* @return Stage\Facet
*/
public function facet()
{
return $this->builder->facet();
}

/**
* Outputs documents in order of nearest to farthest from a specified point.
* You can only use this as the first stage of a pipeline.
Expand All @@ -86,6 +153,21 @@ public function getPipeline()
return $this->builder->getPipeline();
}

/**
* Performs a recursive search on a collection, with options for restricting
* the search by recursion depth and query filter.
*
* @see https://docs.mongodb.org/manual/reference/operator/aggregation/graphLookup/
*
* @param string $from Target collection for the $graphLookup operation to
* search, recursively matching the connectFromField to the connectToField.
* @return Stage\GraphLookup
*/
public function graphLookup($from)
{
return $this->builder->graphLookup($from);
}

/**
* Groups documents by some specified expression and outputs to the next
* stage a document for each distinct grouping.
Expand Down Expand Up @@ -193,6 +275,24 @@ public function redact()
return $this->builder->redact();
}

/**
* Promotes a specified document to the top level and replaces all other
* fields.
*
* The operation replaces all existing fields in the input document,
* including the _id field. You can promote an existing embedded document to
* the top level, or create a new document for promotion.
*
* @param string|null $expression Optional. A replacement expression that
* resolves to a document.
*
* @return Stage\ReplaceRoot
*/
public function replaceRoot($expression = null)
{
return $this->builder->replaceRoot($expression);
}

/**
* Randomly selects the specified number of documents from its input.
*
Expand Down Expand Up @@ -220,6 +320,20 @@ public function skip($skip)
return $this->builder->skip($skip);
}

/**
* Groups incoming documents based on the value of a specified expression,
* then computes the count of documents in each distinct group.
*
* @see http://docs.mongodb.org/manual/reference/operator/aggregation/sortByCount/
*
* @param string $expression The expression to group by
* @return Stage\SortByCount
*/
public function sortByCount($expression)
{
return $this->builder->sortByCount($expression);
}

/**
* Sorts all input documents and returns them to the pipeline in sorted order.
*
Expand Down
Loading

0 comments on commit 1334741

Please sign in to comment.