Commit d7ba99e4 authored by Katherine Walker's avatar Katherine Walker Committed by GitHub

PHPLIB-53 Add documentation for mapReduce (#419)

PHPLIB-53 Add documentation for mapReduce
parent 403cce2e
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: bypassDocumentValidation
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: collation
---
arg_name: option
name: finalize
type: :php:`MongoDB\\BSON\\Javascript <class.mongodb-bson-javascript>`
description: |
Follows the reduce method and modifies the output.
interface: phpmethod
operation: ~
optional: true
---
arg_name: option
name: jsMode
type: boolean
description: |
Specifies whether to convert intermediate data into BSON format between the
execution of the map and reduce functions. The default is ``false``.
interface: phpmethod
operation: ~
optional: true
---
arg_name: option
name: limit
type: integer
description: |
Specifies a maximum number of documents for the input into the map function.
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-common-option.yaml
ref: maxTimeMS
---
arg_name: option
name: query
type: document
description: |
Specifies the selection criteria using query operators for determining the
documents input to the map function.
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: readConcern
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: readPreference
---
arg_name: option
name: scope
type: document
description: |
Specifies global variables that are accessible in the map, reduce, and finalize
functions.
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBCollection-method-find-option.yaml
ref: sort
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: typeMap
---
arg_name: option
name: verbose
type: boolean
description: |
Specifies whether to include the timing information in the result information.
The default is ``true``.
interface: phpmethod
operation: ~
optional: true
---
source:
file: apiargs-MongoDBCollection-common-option.yaml
ref: writeConcern
...
arg_name: param
name: $map
type: :php:`MongoDB\\BSON\\Javascript <mongodb-bson-javascript>`
description: |
A JavaScript function that associates or "maps" a value with a key and emits
the key and value pair.
interface: phpmethod
operation: ~
optional: false
---
arg_name: param
name: $reduce
type: :php:`MongoDB\\BSON\\Javascript <class.mongodb-bson-javascript>`
description: |
A JavaScript function that "reduces" to a single object all the values
associated with a particular key.
interface: phpmethod
operation: ~
optional: false
---
arg_name: param
name: $out
type: string|document
description: |
Specifies where to output the result of the map-reduce operation. You can
either output to a collection or return the result inline. On a primary member
of a replica set you can output either to a collection or inline, but on a
secondary, only inline output is possible.
interface: phpmethod
operation: ~
optional: false
---
source:
file: apiargs-common-param.yaml
ref: $options
...
...@@ -87,6 +87,7 @@ Methods ...@@ -87,6 +87,7 @@ Methods
/reference/method/MongoDBCollection-insertMany /reference/method/MongoDBCollection-insertMany
/reference/method/MongoDBCollection-insertOne /reference/method/MongoDBCollection-insertOne
/reference/method/MongoDBCollection-listIndexes /reference/method/MongoDBCollection-listIndexes
/reference/method/MongoDBCollection-mapReduce
/reference/method/MongoDBCollection-replaceOne /reference/method/MongoDBCollection-replaceOne
/reference/method/MongoDBCollection-updateMany /reference/method/MongoDBCollection-updateMany
/reference/method/MongoDBCollection-updateOne /reference/method/MongoDBCollection-updateOne
......
=================================
MongoDB\\Collection::mapReduce()
=================================
.. default-domain:: mongodb
.. contents:: On this page
:local:
:backlinks: none
:depth: 1
:class: singlecol
Definition
----------
.. phpmethod:: MongoDB\\Collection::mapReduce()
The :manual:`mapReduce </reference/command/mapReduce>` command allows you to
run map-reduce aggregation operations over a collection.
.. code-block:: php
function mapReduce($map, $reduce, $out, array $options = []): MongoDB\MapReduceResult
This method has the following parameters:
.. include:: /includes/apiargs/MongoDBCollection-method-mapReduce-param.rst
The ``$options`` parameter supports the following options:
.. include:: /includes/apiargs/MongoDBCollection-method-mapReduce-option.rst
Return Values
-------------
A :phpclass:`MongoDB\\MapReduceResult` object, which allows for iteration of
mapReduce results irrespective of the output method (e.g. inline, collection)
via the :php:`IteratorAggregate <iteratoraggregate>` interface. It also
provides access to command statistics.
Errors/Exceptions
-----------------
.. include:: /includes/extracts/error-unsupportedexception.rst
.. include:: /includes/extracts/error-invalidargumentexception.rst
.. include:: /includes/extracts/error-unexpectedvalueexception.rst
.. include:: /includes/extracts/error-driver-runtimeexception.rst
Behavior
--------
In MongoDB, the map-reduce operation can write results to a collection
or return the results inline. If you write map-reduce output to a
collection, you can perform subsequent map-reduce operations on the
same input collection that merge replace, merge, or reduce new results
with previous results. See :manual:`Map-Reduce </core/map-reduce>` and
:manual:`Perform Incremental Map-Reduce </tutorial/perform-incremental-map-reduce>`
for details and examples.
When returning the results of a map-reduce operation *inline*, the
result documents must be within the :limit:`BSON Document Size` limit,
which is currently 16 megabytes.
MongoDB supports map-reduce operations on :manual:`sharded collections
</sharding>`. Map-reduce operations can also output
the results to a sharded collection. See
:manual:`Map-Reduce and Sharded Collections </core/map-reduce-sharded-collections>`.
Example
-------
This example will use city populations to calculate the overall population of
each state.
.. code-block:: php
<?php
$collection = (new MongoDB\Client)->test->zips;
$map = new MongoDB\BSON\Javascript('function() { emit(this.state, this.pop); }');
$reduce = new MongoDB\BSON\Javascript('function(key, values) { return Array.sum(values) }');
$out = ['inline' => 1];
$populations = $collection->mapReduce($map, $reduce, $out);
foreach ($populations as $pop) {
var_dump($pop);
};
The output would then resemble::
object(stdClass)#2293 (2) {
["_id"]=>
string(2) "AK"
["value"]=>
float(544698)
}
object(stdClass)#2300 (2) {
["_id"]=>
string(2) "AL"
["value"]=>
float(4040587)
}
object(stdClass)#2293 (2) {
["_id"]=>
string(2) "AR"
["value"]=>
float(2350725)
}
object(stdClass)#2300 (2) {
["_id"]=>
string(2) "AZ"
["value"]=>
float(3665228)
}
See Also
--------
- :manual:`mapReduce </reference/command/mapReduce>` command reference in the MongoDB
manual
- :manual:`Map-Reduce </core/map-reduce>` documentation in the MongoDB manual
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
namespace MongoDB; namespace MongoDB;
use MongoDB\BSON\JavascriptInterface;
use MongoDB\Driver\Cursor; use MongoDB\Driver\Cursor;
use MongoDB\Driver\Manager; use MongoDB\Driver\Manager;
use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadConcern;
...@@ -44,6 +45,7 @@ use MongoDB\Operation\FindOneAndUpdate; ...@@ -44,6 +45,7 @@ use MongoDB\Operation\FindOneAndUpdate;
use MongoDB\Operation\InsertMany; use MongoDB\Operation\InsertMany;
use MongoDB\Operation\InsertOne; use MongoDB\Operation\InsertOne;
use MongoDB\Operation\ListIndexes; use MongoDB\Operation\ListIndexes;
use MongoDB\Operation\MapReduce;
use MongoDB\Operation\ReplaceOne; use MongoDB\Operation\ReplaceOne;
use MongoDB\Operation\UpdateMany; use MongoDB\Operation\UpdateMany;
use MongoDB\Operation\UpdateOne; use MongoDB\Operation\UpdateOne;
...@@ -809,6 +811,56 @@ class Collection ...@@ -809,6 +811,56 @@ class Collection
return $operation->execute($server); return $operation->execute($server);
} }
/**
* Executes a map-reduce aggregation on the collection.
*
* @see MapReduce::__construct() for supported options
* @see http://docs.mongodb.org/manual/reference/command/mapReduce/
* @param JavascriptInterface $map Map function
* @param JavascriptInterface $reduce Reduce function
* @param string|array|object $out Output specification
* @param array $options Command options
* @return MapReduceResult
* @throws UnsupportedException if options are not supported by the selected server
* @throws InvalidArgumentException for parameter/option parsing errors
* @throws DriverRuntimeException for other driver errors (e.g. connection errors)
* @throws UnexpectedValueException if the command response was malformed
*/
public function mapReduce(JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
{
$hasOutputCollection = ! $this->isOutInline($out);
if ( ! isset($options['readPreference'])) {
$options['readPreference'] = $this->readPreference;
}
// Check if the out option is inline because we will want to coerce a primary read preference if not
if ($hasOutputCollection) {
$options['readPreference'] = new ReadPreference(ReadPreference::RP_PRIMARY);
}
$server = $this->manager->selectServer($options['readPreference']);
/* A "majority" read concern is not compatible with inline output, so
* avoid providing the Collection's read concern if it would conflict.
*/
if ( ! isset($options['readConcern']) && ! ($hasOutputCollection && $this->readConcern->getLevel() === ReadConcern::MAJORITY) && \MongoDB\server_supports_feature($server, self::$wireVersionForReadConcern)) {
$options['readConcern'] = $this->readConcern;
}
if ( ! isset($options['typeMap'])) {
$options['typeMap'] = $this->typeMap;
}
if (! isset($options['writeConcern']) && \MongoDB\server_supports_feature($server, self::$wireVersionForWritableCommandWriteConcern)) {
$options['writeConcern'] = $this->writeConcern;
}
$operation = new MapReduce($this->databaseName, $this->collectionName, $map, $reduce, $out, $options);
return $operation->execute($server);
}
/** /**
* Replaces at most one document matching the filter. * Replaces at most one document matching the filter.
* *
...@@ -903,4 +955,19 @@ class Collection ...@@ -903,4 +955,19 @@ class Collection
return new Collection($this->manager, $this->databaseName, $this->collectionName, $options); return new Collection($this->manager, $this->databaseName, $this->collectionName, $options);
} }
private function isOutInline($out)
{
if ( ! is_array($out) && ! is_object($out)) {
return false;
}
$out = (array) $out;
if (key($out) === 'inline') {
return true;
}
return false;
}
} }
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
namespace MongoDB\Operation; namespace MongoDB\Operation;
use MongoDB\BSON\Javascript; use MongoDB\BSON\JavascriptInterface;
use MongoDB\Driver\Command; use MongoDB\Driver\Command;
use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadConcern;
use MongoDB\Driver\ReadPreference; use MongoDB\Driver\ReadPreference;
...@@ -130,13 +130,13 @@ class MapReduce implements Executable ...@@ -130,13 +130,13 @@ class MapReduce implements Executable
* *
* @param string $databaseName Database name * @param string $databaseName Database name
* @param string $collectionName Collection name * @param string $collectionName Collection name
* @param Javascript $map Map function * @param JavascriptInterface $map Map function
* @param Javascript $reduce Reduce function * @param JavascriptInterface $reduce Reduce function
* @param string|array|object $out Output specification * @param string|array|object $out Output specification
* @param array $options Command options * @param array $options Command options
* @throws InvalidArgumentException for parameter/option parsing errors * @throws InvalidArgumentException for parameter/option parsing errors
*/ */
public function __construct($databaseName, $collectionName, Javascript $map, Javascript $reduce, $out, array $options = []) public function __construct($databaseName, $collectionName, JavascriptInterface $map, JavascriptInterface $reduce, $out, array $options = [])
{ {
if ( ! is_string($out) && ! is_array($out) && ! is_object($out)) { if ( ! is_string($out) && ! is_array($out) && ! is_object($out)) {
throw InvalidArgumentException::invalidType('$out', $out, 'string or array or object'); throw InvalidArgumentException::invalidType('$out', $out, 'string or array or object');
......
...@@ -2,11 +2,13 @@ ...@@ -2,11 +2,13 @@
namespace MongoDB\Tests\Collection; namespace MongoDB\Tests\Collection;
use MongoDB\BSON\Javascript;
use MongoDB\Collection; use MongoDB\Collection;
use MongoDB\Driver\BulkWrite; use MongoDB\Driver\BulkWrite;
use MongoDB\Driver\ReadConcern; use MongoDB\Driver\ReadConcern;
use MongoDB\Driver\ReadPreference; use MongoDB\Driver\ReadPreference;
use MongoDB\Driver\WriteConcern; use MongoDB\Driver\WriteConcern;
use MongoDB\Operation\MapReduce;
/** /**
* Functional tests for the Collection class. * Functional tests for the Collection class.
...@@ -180,6 +182,28 @@ class CollectionFunctionalTest extends FunctionalTestCase ...@@ -180,6 +182,28 @@ class CollectionFunctionalTest extends FunctionalTestCase
$this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW()); $this->assertSame(WriteConcern::MAJORITY, $debug['writeConcern']->getW());
} }
public function testMapReduce()
{
$this->createFixtures(3);
$map = new Javascript('function() { emit(1, this.x); }');
$reduce = new Javascript('function(key, values) { return Array.sum(values); }');
$out = ['inline' => 1];
$result = $this->collection->mapReduce($map, $reduce, $out);
$this->assertInstanceOf('MongoDB\MapReduceResult', $result);
$expected = [
[ '_id' => 1.0, 'value' => 66.0 ],
];
$this->assertSameDocuments($expected, $result);
$this->assertGreaterThanOrEqual(0, $result->getExecutionTimeMS());
$this->assertNotEmpty($result->getCounts());
$this->assertNotEmpty($result->getTiming());
}
/** /**
* Create data fixtures. * Create data fixtures.
* *
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment