Grouping & Sorting in MongoDB

Will man mit PHP und MongoDB soetwas wie “SQL Aggregate Functions” umsetzen muss man sich etwas verbiegen.

MongoDb hat zwar eine group() function, die in etwa SQLs GROUP BY entspricht, allerdings kann man dies nicht kombinieren mit SORT oder LIMIT bzw den sort() und limit() Funktionen, da diese keinen Cursor zurückgibt sondern direkt ein Array.

Will man also sortieren und limitieren muss man sich des Map / Reduce features von MongoDB bedienen.

Ein Query wie folgt:

SELECT referer.URL, count(*) AS cnt
FROM `referer`
GROUP BY referer.URL
ORDER BY cnt ASC LIMIT 25

…wird dann über Command() so umgesetzt:

$map = new MongoCode("function() { emit(this.url,1); }");
$reduce = new MongoCode("function(k, vals) { ".
			"var sum = 0;".
			"for (var i in vals) {".
			"sum += vals[i];". 
			"}".
			"return sum; }");
$r = $this->db_handler->command(array(
		    	"mapreduce" => "referer", 
		    	"map" => $map,
		    	"reduce" => $reduce));
$r = $this->db_handler->selectCollection($r['result'])->find();
$r->sort(array('value' => -1));
$r->limit(25);
$data = array();
foreach ($r as $ref) {
	$data[$ref['_id']] = $ref['value'];
}
return $data;

In die Reduce Funktion kann man sämtliche Abfrage-Logik packen, was es zu einem ziemlich mächtigem Konstrukt macht.
Hat man sich einmal dran gewöhnt, lässt sich eine Menge damit anstellen.

Danke auch an diesen Blog.