【问题标题】:MongoDB, PHP getting unique visitors per dayMongoDB、PHP 每天都有独立访问者
【发布时间】:2013-09-17 20:42:55
【问题描述】:

我正在使用 PHP 和 MongoDB 创建一些分析脚本,但我有点卡住了。我想在特定时间范围内获得每天唯一的访问者数量。

{
   "_id": ObjectId("523768039b7e7a1505000000"),
   "ipAddress": "127.0.0.1",
   "pageId": ObjectId("522f80f59b7e7a0f2b000000"),
   "uniqueVisitorId": "0445905a-4015-4b70-a8ef-b339ab7836f1",
   "recordedTime": ISODate("2013-09-16T20:20:19.0Z") 
}

要过滤的字段是 uniqueVisitorId 和recordedTime。

我在 PHP 中创建了一个我初始化的数据库对象,它在构造对象时使我建立了一个数据库连接,然后我使用在对象构造时创建的数据库连接将 MongoDB php 函数简单地映射到公共函数。

无论如何,到目前为止,我得到了每天的访问者数量:

public function GetUniqueVisitorsDiagram() {
    // MAP
    $map = new MongoCode('function() {
        day = new Date(Date.UTC(this.recordedTime.getFullYear(), this.recordedTime.getMonth(), this.recordedTime.getDate()));
        emit({day: day, uniqueVisitorId:this.uniqueVisitorId},{count:1});
    }');
    // REDUCE
    $reduce = new MongoCode("function(key, values) {
            var count = 0;
            values.forEach(function(v) {
                count += v['count'];
            });
            return {count: count};
        }");
    // STATS
    $stats = $this->database->Command(array(
        'mapreduce' => 'statistics',
        'map' => $map,
        'reduce' => $reduce,
        "query" => array(
            "recordedTime" =>
                array(
                    '$gte' => $this->startDate,
                    '$lte' => $this->endDate
                )
            ),
            "out" => array(
                "inline" => 1
            )
        ));
    return $stats;          
}

如何正确过滤这些数据以获取唯一身份访问者?或者使用聚合会更好,如果可以的话,你能帮我写一个代码 sn-p 吗?

【问题讨论】:

  • 我强烈建议您不要将 Map Reduce 内联到您的应用程序中,查看聚合框架之类的东西
  • 你将如何进行聚合?在我看来,我无法使用聚合框架轻松过滤,在我看来,我需要执行两个请求。

标签: php mongodb mapreduce distinct


【解决方案1】:

聚合框架中的 $group 运算符正是为这个用例而设计的,并且可能会快 10 到 100 倍。在此处阅读组操作员:http://docs.mongodb.org/manual/reference/aggregation/group/

还有这里的php驱动实现:http://php.net/manual/en/mongocollection.aggregate.php

您可以将 $group 运算符与其他运算符结合使用,以进一步限制您的聚合。您最好自己阅读一下框架,以更好地了解正在发生的事情,因此我不会为您发布完整的示例。

【讨论】:

    【解决方案2】:
        $m=new MongoClient();
        $db=$m->super_test;
        $db->gjgjgjg->insert(array(
            "ipAddress" => "127.0.0.1",
            "pageId" => new MongoId("522f80f59b7e7a0f2b000000"),
            "uniqueVisitorId" => "0445905a-4015-4b70-a8ef-b339ab7836f1",
            "recordedTime" => new MongoDate(strtotime("2013-09-16T20:20:19.0Z"))
        ));
        var_dump($db->gjgjgjg->find(array('recordedTime'=>array('$lte'=>new MongoDate(),'$gte'=>new MongoDate(strtotime('-1 week')))))->count()); // Prints 1
        $res=$db->gjgjgjg->aggregate(array(
                array('$match'=>array('recordedTime'=>array('$lte'=>new MongoDate(),'$gte'=>new MongoDate(strtotime('-1 week'))),'uniqueVisitorId'=>array('$ne'=>null))),
                array('$project'=>array('day'=>array('$dayOfMonth'=>'$recordedTime'),'month'=>array('$month'=>'$recordedTime'),'year'=>array('$year'=>'$recordedTime'))),
                array('$group'=>array('_id'=>array('day'=>'$day','month'=>'$month','year'=>'$year'), 'c'=>array('$sum'=>1)))
        )); 
        var_dump($res['result']);
    

    完整回答问题:

        $m=new MongoClient();
        $db=$m->super_test;
        $db->gjgjgjg->insert(array(
            "ipAddress" => "127.0.0.1",
            "pageId" => new MongoId("522f80f59b7e7a0f2b000000"),
            "uniqueVisitorId" => "0445905a-4015-4b70-a8ef-b339ab7836f1",
            "recordedTime" => new MongoDate(strtotime("2013-09-16T20:20:19.0Z"))
        ));
        var_dump($db->gjgjgjg->find(array('recordedTime'=>array('$lte'=>new MongoDate(),'$gte'=>new MongoDate(strtotime('-1 week')))))->count()); // Prints 1
        $res=$db->gjgjgjg->aggregate(array(
                array('$match'=>array('recordedTime'=>array('$lte'=>new MongoDate(),'$gte'=>new MongoDate(strtotime('-1 week'))),'uniqueVisitorId'=>array('$ne'=>null))),
                array('$project'=>array('day'=>array('$dayOfMonth'=>'$recordedTime'),'month'=>array('$month'=>'$recordedTime'),'year'=>array('$year'=>'$recordedTime'))),
                array('$group'=>array('_id'=>array('day'=>'$day','month'=>'$month','year'=>'$year','v'=>'$uniqueVisitorId'), 'c'=>array('$sum'=>1))),
                array('$group'=>array('_id'=>array('day'=>'$_id.day','month'=>'$_id.month','year'=>'$_id.year'),'c'=>array('$sum'=>1)))
        )); 
        var_dump($res['result']);
    

    我相信你正在寻找的东西接近那个。

    它将返回一组以 _id 作为日期的文档,然后计算当天的唯一身份访问者数量,而与 ID 无关,它仅检测 ID 是否存在。

    由于您每天都需要它,因此您实际上可以将 dat 部分换成 $dayOfYear 的一个字段,我认为。

    【讨论】:

    • 嗨@sammaye,感谢您的反馈。使用您发布的内容,我设法从 Mongo 获得了一些信息。但是,当我添加 $match 条件时,它会停止工作。任何的想法? $criterea = array( array( '$project' => array('day' => array('$dayOfMonth'=>'$recordedTime'), 'month' => array('$month'=>'$recordedTime '), '年' => 数组('$year'=>'$recordedTime') ) ), 数组('$group' => 数组('_id' => 数组('day' => '$day' , '月' => '$month', 'year' => '$year' ), 'c' => array( '$sum'=>1 ) ) ) );
    • 我试图将“$match”作为第二个参数添加到 PHP 中的聚合函数,但我得到的是一个错误:管道元素 0 不是对象,没有第二个论点,没有 $match 它可以工作,但我得到了太多的数据。
    • @MarcWitteveen 是的,match 是聚合框架中的一个运算符,让我们分解一下 $match,如果去掉uniqueVisitorId 子句会发生什么?还要确保将MongoDate 放入开始和结束日期。如果您在find() 中单独尝试查询,它会起作用吗?
    • 当我这样做时(见下面的代码)我得到了前面提到的错误:$criterea = array( array( '$project' => array( .... ) ), array( '$group' => array( .... ), 'c' => array( .... ) ) ) ); $op = array( '$match' => array( 'recordedTime' => array( '$gte' => $this->startDate, '$lte' => $this->endDate ) ) ); $stats = $this->database->Aggregate("statistics", $criterea, $op);
    • 聚合函数如下所示:public function Aggregate($collection, $criteria, $op = array()) { $db = $this->dbObject; try { $cursor = $db->$collection->aggregate($criteria, $op); return $cursor; } catch (Exception $e) { $this->errorLog[] = $e->getMessage(); } } 当我仅使用 $match 部分作为标准时,过滤器起作用并且我在两个日期之间获得数据。
    猜你喜欢
    • 2015-04-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多