Ver código fonte

Implement aggregate() and aggregateCursor()

Andreas Braun 10 anos atrás
pai
commit
512670e39b

+ 12 - 3
lib/Alcaeus/MongoDbAdapter/TypeConverter.php

@@ -37,8 +37,7 @@ class TypeConverter
         $result = [];
 
         foreach ($object as $key => $value) {
-            // TODO: maybe add a more meaningful check instead of stdClass?
-            $result[$key] = ($value instanceof \stdClass) ? static::convertObjectToLegacyArray($value) : static::convertToLegacyType($value);
+            $result[$key] = ($value instanceof \stdClass || is_array($value)) ? static::convertObjectToLegacyArray($value) : static::convertToLegacyType($value);
         }
 
         return $result;
@@ -67,6 +66,15 @@ class TypeConverter
     }
 
     /**
+     * @param array $array
+     * @return bool
+     */
+    public static function isNumericArray(array $array)
+    {
+        return $array === [] || is_numeric(array_keys($array)[0]);
+    }
+
+    /**
      * Converts all arrays with non-numeric keys to stdClass
      *
      * @param array $array
@@ -74,7 +82,8 @@ class TypeConverter
      */
     private static function ensureCorrectType(array $array)
     {
-        if ($array === [] || is_numeric(array_keys($array)[0])) {
+        // Empty arrays are left untouched since they may be an empty list or empty document
+        if (static::isNumericArray($array)) {
             return $array;
         }
 

+ 43 - 4
lib/Mongo/MongoCollection.php

@@ -103,9 +103,34 @@ class MongoCollection
      * @param array $pipelineOperators
      * @return array
      */
-    public function aggregate(array $pipeline, array $op, array $pipelineOperators)
+    public function aggregate(array $pipeline, array $op = [] /* , array $pipelineOperators, ... */)
     {
-        $this->notImplemented();
+        if (! TypeConverter::isNumericArray($pipeline)) {
+            $pipeline = [];
+            $options = [];
+
+            $i = 0;
+            foreach (func_get_args() as $operator) {
+                $i++;
+                if (! is_array($operator)) {
+                    trigger_error("Argument $i is not an array", E_WARNING);
+                    return;
+                }
+
+                $pipeline[] = $operator;
+            }
+        } else {
+            $options = $op;
+        }
+
+        $command = [
+            'aggregate' => $this->name,
+            'pipeline' => $pipeline
+        ];
+
+        $command += $options;
+
+        return $this->db->command($command, [], $hash);
     }
 
     /**
@@ -114,9 +139,23 @@ class MongoCollection
      * @param array $options
      * @return MongoCommandCursor
      */
-    public function aggregateCursor(array $pipeline, array $options)
+    public function aggregateCursor(array $pipeline, array $options = [])
     {
-        $this->notImplemented();
+        // Build command manually, can't use mongo-php-library here
+        $command = [
+            'aggregate' => $this->name,
+            'pipeline' => $pipeline
+        ];
+
+        // Convert cursor option
+        if (! isset($options['cursor']) || $options['cursor'] === true || $options['cursor'] === []) {
+            // Cursor option needs to be an object convert bools and empty arrays since those won't be handled by TypeConverter
+            $options['cursor'] = new \stdClass;
+        }
+
+        $command += $options;
+
+        return new MongoCommandCursor($this->db->getConnection(), (string) $this, $command);
     }
 
     /**

+ 59 - 0
tests/Alcaeus/MongoDbAdapter/MongoCollectionTest.php

@@ -51,6 +51,65 @@ class MongoCollectionTest extends TestCase
         $this->assertSame(1, $collection->count(['foo' => 'bar']));
     }
 
+    public function testAggregate()
+    {
+        $collection = $this->getCollection();
+
+        $collection->insert(['foo' => 'bar']);
+        $collection->insert(['foo' => 'bar']);
+        $collection->insert(['foo' => 'foo']);
+
+        $pipeline = [
+            [
+                '$group' => [
+                    '_id' => '$foo',
+                    'count' => [ '$sum' => 1 ],
+                ],
+            ],
+            [
+                '$sort' => ['_id' => 1]
+            ]
+        ];
+
+        $result = $collection->aggregate($pipeline);
+        $this->assertInternalType('array', $result);
+        $this->assertArrayHasKey('result', $result);
+
+        $this->assertEquals([
+            ['_id' => 'bar', 'count' => 2],
+            ['_id' => 'foo', 'count' => 1],
+        ], $result['result']);
+    }
+
+    public function testAggregateCursor()
+    {
+        $collection = $this->getCollection();
+
+        $collection->insert(['foo' => 'bar']);
+        $collection->insert(['foo' => 'bar']);
+        $collection->insert(['foo' => 'foo']);
+
+        $pipeline = [
+            [
+                '$group' => [
+                    '_id' => '$foo',
+                    'count' => [ '$sum' => 1 ],
+                ],
+            ],
+            [
+                '$sort' => ['_id' => 1]
+            ]
+        ];
+
+        $cursor = $collection->aggregateCursor($pipeline);
+        $this->assertInstanceOf('MongoCommandCursor', $cursor);
+
+        $this->assertEquals([
+            ['_id' => 'bar', 'count' => 2],
+            ['_id' => 'foo', 'count' => 1],
+        ], iterator_to_array($cursor));
+    }
+
     /**
      * @return \MongoCollection
      */