使用命令的MapReduce无法从服务器解码文档



我有一个Test数据库,其中一个名为 collection

的集合
 {
    "_id": "576008e5b47a6120c800418d",
    "UserID": "Paul",
    "Page": "A"
 }

我想记录网络效果并使用mapReduce获得

之类的结果
{
    "_id": "Paul",
    "value": {
        "A": 1,
        "B": 0,
        "C": 0,
        "D": 0,
        "E": 0
    }
}

开始,我尝试了使用php 7 mongodb驱动程序1.1.7使用命令的简单代码,该命令未能从服务器解码文档:

<?php
$manager = new MongoDBDriverManager("mongodb://localhost:27017");
$command = new MongoDBDriverCommand(array(
  "mapReduce" => "collection",
  "map" => "function() { emit(this.UserID, 1); }",
  "reduce" => "function(Users, Pages){".
  "return Pages;}",
  "out" => "ex"
));
try {
  $cursor = $manager->executeCommand('Test.collection', $command);
  $response = $cursor->toArray()[0];
} catch(MongoDBDriverException $e) {
  echo $e->getMessage(), "n";
  exit;
}
var_dump($response);
?>

任何想法都将不胜感激。

不太确定我是否会推荐MapReduce进行此类操作,会说聚合框架将以更好的性能来完成聚合到JavaScript进行编译(在MapReduce情况下)。

使用聚合操作,您所需要的只是 $group 管道,它使用 $cond 运算符,它允许您将逻辑条件转换为值。在这种情况下,您需要将pages指定为键,将其计数为值,并将文档分组为UserID

考虑在Mongo Shell中运行以下聚合操作:


db.collection.aggregate([
    {
        "$group": {
            "_id": "$UserID",
            "A": { 
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$Page", "A" ] },
                        1,
                        0
                    ]
                }
            },
            "B": { 
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$Page", "B" ] },
                        1,
                        0
                    ]
                }
            },
            "C": { 
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$Page", "C" ] },
                        1,
                        0
                    ]
                }
            },
            "D": { 
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$Page", "D" ] },
                        1,
                        0
                    ]
                }
            },
            "E": { 
                "$sum": {
                    "$cond": [
                        { "$eq": [ "$Page", "E" ] },
                        1,
                        0
                    ]
                }
            }
        }
    }
])

将产生输出:

{
    "_id": "Paul",    
    "A": 1,
    "B": 0,
    "C": 0,
    "D": 0,
    "E": 0    
}

对于上述示例文档。


对于简洁起见,如果假设您有事先的页面列表,则可以动态产生管道如下:

var groupOperation = { "$group": { "_id": "$UserID" } },
    pages = ["A", "B", "C", "D", "E"];
pages.forEach(function (page){
    groupOperation["$group"][page] = {
        "$sum": {
            "$cond": [
                { "$eq": [ "$Page", page ] },
                1,
                0
            ]
        }
    };
})
db.collection.aggregate([groupOperation]);

现在,将其转换为PHP如下:

<?php
$group_pipeline = [
    '$group' => [
        '_id' => '$UserID',
        'A' =>  [ 
            '$sum' =>  [
                '$cond' =>  [ [ '$eq' =>  [ '$Page', 'A' ] ], 1, 0 ]
            ]
        ],
        'B' =>  [ 
            '$sum' =>  [
                '$cond' =>  [ [ '$eq' =>  [ '$Page', 'B' ] ], 1, 0 ]
            ]
        ],
        'C' =>  [ 
            '$sum' =>  [
                '$cond' =>  [ [ '$eq' =>  [ '$Page', 'C' ] ], 1, 0 ]
            ]
        ],
        'D' =>  [ 
            '$sum' =>  [
                '$cond' =>  [ [ '$eq' =>  [ '$Page', 'D' ] ], 1, 0 ]
            ]
        ],
        'E' =>  [ 
            '$sum' =>  [
                '$cond' =>  [ [ '$eq' =>  [ '$Page', 'E' ] ], 1, 0 ]
            ]
        ]
    ],
];
$aggregation = $collection->aggregate([ group_pipeline ]);
?>

是否应该坚持使用MapReduce,然后考虑更改地图并将功能降低为:

db.collection.mapReduce(
    function() {
        var obj = {};
        ["A", "B", "C", "D", "E"].forEach(function (page){ obj[page] = 0; } ); 
        obj[this.Page] = 1;        
        emit(this.UserID, obj);
    },
    function(key, values) {
        var obj = {};
        values.forEach(function(value) {
            Object.keys(value).forEach(function(key) {
                if (!obj.hasOwnProperty(key)){
                    obj[key] = 0;
                } 
                obj[key]++;
            });
        });
        return obj;
    },
    { "out": { "inline": 1 } }
)

给出输出:

{
    "results" : [ 
        {
            "_id" : "Paul",
            "value" : {
                "A" : 1,
                "B" : 0,
                "C" : 0,
                "D" : 0,
                "E" : 0
            }
        }
    ]
}

将上述MAPREDUCE操作转换为PHP是微不足道的。

最新更新