Map ReduceΒΆ
The Doctrine MongoDB ODM fully supports the map reduce functionality via its Query Builder API.
Note
From the MongoDB manual:
Map-reduce is a data processing paradigm for condensing large volumes of data into useful aggregated results. In MongoDB, map-reduce operations use custom JavaScript functions to map, or associate, values to a key. If a key has multiple values mapped to it, the operation reduces the values for the key to a single object.
Imagine a situation where you had an application with a document
named Event
and it was related to a User
document:
<?php
namespace Documents;
/** @Document */
class Event
{
/** @Id */
private $id;
/** @ReferenceOne(targetDocument="Documents\User") */
private $user;
/** @Field(type="string") */
private $type;
/** @Field(type="date") */
private $date;
/** @Field(type="string") */
private $description;
// getters and setters
}
/** @Document */
class User
{
// ...
}
We may have a situation where we want to run a query that tells us how many sales events each user has had. We can easily use the map reduce functionality of MongoDB via the ODM's query builder. Here is a simple map reduce example:
<?php
$qb = $dm->createQueryBuilder('Documents\User')
->field('type')
->equals('sale')
->map('function() { emit(this.user.$id, 1); }')
->reduce('function(k, vals) {
var sum = 0;
for (var i in vals) {
sum += vals[i];
}
return sum;
}');
$query = $qb->getQuery();
$results = $query->execute();
foreach ($results as $user) {
printf("User %s had %d sale(s).\n", $user['_id'], $user['value']);
}
Note
The query builder also has a finalize()
method, which may be used to
specify a finalize function to be executed after the reduce step.
When using map reduce with Doctrine, the results are not hydrated into objects. Instead, the raw results are returned directly from MongoDB.
The preceding example is equivalent to executing the following command via the PHP driver directly:
<?php
$db = $mongoClient->selectDB('my_db');
$map = new MongoCode('function() { emit(this.user.$id, 1); }');
$reduce = new MongoCode('function(k, vals) {
var sum = 0;
for (var i in vals) {
sum += vals[i];
}
return sum;
}');
$result = $db->command(array(
'mapreduce' => 'events',
'map' => $map,
'reduce' => $reduce,
'query' => array('type' => 'sale'),
));
foreach ($result['results'] as $user) {
printf("User %s had %d sale(s).\n", $user['_id'], $user['value']);
}