`

PHP+MongoDB组合来做访问统计

阅读更多

MongoDB是一款现在非常流行的NoSql引擎。我看上的原因有两点。
1、完美支持php。非常丰富的接口。
2、高并发的插入和写入对比mysql有极大的优势。我测试过。搜索平均是2.5倍。插入和update是10倍左右。数据就不贴上来了。
但也有很多限制。32位系统,单文件大小不能超过2G。。。插入数据的时候比较依赖内存,内存太小得把虚拟内存搞大点或者完全删除掉虚拟内存的限制
安装、介绍以及手册:www.mongodb.com   资源非常丰富。
上代码
class MDBBrowser{
        //链接
        private $connect;

        private $db = null;
        protected $table_name = "statistic";
        protected $collection = "browser";
        protected $memStorage = null;

        //服务器信息
        private $config = array(
                                                "host"     => "localhost",  //服务器
                                                "user"     => "sampeng",    //用户名
                                                "password" => "这里是你的密码",   //密码
                                                "unique"   => false         //唯一性
                                                 );
                                                 
        public function __construct(){
                $this->connect();
                $this->selectDB();
                if($this->config['unique']){
                        //TODO增加用户唯一性
                        $this->intMemStorage();
                }
        }
        /**
         * 选择数据库
         * @param $name 数据库名
         * @return 返回collection对象
         */
        public function table($name){
                $this->collection = $name;
                return $this->collection;
        }
        
        /**
         * 存储方法
         * 将appid的需要累计加1的字段自动加1
         * @param  $appid        appid。在命名空间下的应用id
         * @param  $uid          uid.做该操作的用户。这个是用来做限制判断的
         * @param  $field        需要计数的count字段。比如reader。dig。follow等等
         * @param  $namespace    命名空间
         */
        public function storage($appid,$uid,$field = "reader",$namespace = "default"){
                $this->insertAndUpdateTime();
                
                if(! ( $this->config['unique'] && $this->checkUnique($uid,$appid,$namespace)) ) {
                        //检查该项是否存在
                        $count = $this->db->count(array('ns'=>$namespace,'appid'=>$appid));
                        if(0 == $count){
                                $data['ns'] = $namespace;
                                $data['appid'] = $appid;
                                $save[$field] = 0;
                                $result = $this->db->save($data,$save);
                        }else{
                                $data['ns'] = $namespace;
                                $data['appid'] = $appid;
                                $result = $this->db->update($data,array('$inc'=>array($field=>1)));
                                unset($data);
                        }
                }
        }
        
        /**
         * 获得命名空间下的某个资源的统计计数
         * @param $appid
         * @param $field        允许逗号分隔
         * @param $namespace
         */
        public function getCount($appid,$field = 'reader',$namespace = "default"){
                        $map['ns'] = $namespace;
                        $map['appid'] = $appid;
                        $fields = explode(',',$field);
                        $data = $this->db->findOne($map,$fields);
                        array_shift($data);
                        if(1 == count($fields)){
                                $data = $data[$field];
                        }
                        return $data;
        }
        
        /**
         * 给定一个值,单位秒。检查是否超时。
         * 这个是全局的,没有做每个命名空间下的超时检查
         * @param $checkTime 单位秒
         */
        public function checkUpdateTime($checkTime = 300){
                $map['status'] = "extra";
                $data = $this->db->findOne($map,array('insertTime','updateTime'));
                return $data['updateTime'] - $data['insertTime'] >= $checkTime;
        }

        /**
         * 将指定命名空间的所有数据弹出来。返回数组。
         * 此操作将更新初始存储的insertTime和updateTime
         * 
         * @param $namespace  stirng|false false时是所有的数据
         * @param $remove     false|true  true时所有历史数据
         */
        public function popNsData($namespace,$remove = false){
                
                if(!$namespace){
                        //所有ns下的统计数据都取出来
                        $map['status']['$ne'] ='extra';
                }else{
                        //只取一部分
                        $map['ns'] = $namespace;
                }
                $data = $this->db->find($map);
                $result = array();
                while($data->hasNext()){
                        $data->next();
                        $tempData = $data->current();
                        $appId = $tempData['appid'];
                        unset($tempData['_id']);
                        $result[$tempData['ns']][$appId] = $tempData;
                }
                if(!empty($result)){
                        if($remove){
                                $this->db->remove($map);
                        }
                        //修改更新时间
                        $statusWhere['status'] = "extra";
                        
                        $time = time();
                        $statusSave['insertTime'] = $time;
                        $statusSave['updateTime'] = $time;
                        $this->db->update($statusWhere,$statusSave);
                }
                return $result;
        }

        protected function connect(){
                $config = $this->config;
                $this->connect = new Mongo("mongodb://{$config['user']}:{$config['password']}@{$config['host']}");
                return $this;
        }
        
        protected function selectDB(){
                $database = $this->connect->selectDB($this->table_name);        
                $this->db = $database->selectCollection($this->collection);
                return $this->db;
        }
        
        protected function insertAndUpdateTime(){
                $time = time();
                $count = $this->db->count();
                //判断是否有数据
                if(0 == $count){
                        $data['status'] = "extra";
                        $data['insertTime'] = $time;
                        $data['updateTime'] = $time;
                        $this->db->insert($data);
                }else{
                        $where['status'] = "extra";
                        $save['$set']['updateTime'] = $time;
                        $this->db->update($where,$save);
                }
        }
        
}


我的存储结构是这样的
{
  "_id": "4c4be8437f8b9a1b36000000",
  "appid": 1,
  "ns": "default",
  "reader": 15
}
{
  "_id": "4c4bd4197f8b9a9832000000",
  "insertTime": 1280042037,
  "updateTime": 1280042037
}


我想的是还可以这样

{

"_id":XXX

"ns":"default”,

"info1":

       {

         appid:XX,

         reader:XXX

      }

}

就是一个namespace就只用一个数据集完全存储。。查询倒是可以。。只是我觉得这样比较麻烦。扩展也不方便。。还是用平铺的方式存储就够了。。过多的设计就是过度设计- -
比如这个帖子的浏览数就可以这样增加
$a = new MDBBrowser();
$a->storage(1,2,'reader','bbs');

支持和反对的ajax接受方这样处理
$a = new MDBBrowser();
$a->storage(1,2,'dig','bbs');

等等等等。。。
分享到:
评论

相关推荐

    PHP做大数据量实时分析

    - 使用Redis或Memcached这样的内存数据结构存储系统来缓存数据,减少对数据库的直接访问压力。 - 利用PHP扩展,比如MongoDB、RabbitMQ PHP客户端等,这些扩展可以实现PHP与各种系统或服务的高效交互。 - 结合PaaS...

    MongoDB开发使用手册包含LINUX/WINDOWS下面安装使用开发的详细介绍

    这些系统往往由Apache + MySQL + PHP、IIS + ASP + SQL Server、IIS + ASP.NET + SQL Server或TOMCAT + JSP + Oracle等组合构成。 - **博客与去中心化网站**:Web 2.0时代的到来催生了博客等去中心化网站。这些网站...

    基于PHP的搏天短网址生成管理系统网站源码.zip

    MySQL、SQLite或NoSQL数据库如MongoDB可能是选择之一,其中需要设计合适的表结构来存储这些数据。 3. **URL编码与解码**:在处理URL时,需要确保其符合URI标准,因此会用到URL编码(如`encodeURIComponent`)和解码...

    统一数据库系统1

    2. 使用REDIS+mongodb+MYSQL+ES的组合,虽然可以提供不同的功能,但会增加系统的复杂性,需要集成和定制,可能需要编写额外的代码来协调各个组件。 3. SAP HANA是一个高效的分析平台,结合了硬件和软件,提供实时...

    javascript进阶.md

    - **访问方式**:在浏览器中输入`http://ip地址/index.html`来访问服务器上的HTML页面。 #### 四、PHP基础语法 - **Hello World示例** ```php <?php echo "hello, world"; ?> ``` - **语法特点** - **标记**...

    短链接生成带教程源码.

    7. **统计分析**:为了优化服务和提供额外价值,可以添加点击次数统计、来源追踪等功能,以便分析短链接的使用情况。 通过学习和实践这个教程,你可以掌握短链接生成的基本流程,理解前后端交互,以及如何利用H5...

    ThinkPHP5.0完全开发手册.pdf

    手册详细介绍了ThinkPHP5.0的安装、开发规范、目录结构、生命周期、入口文件、URL访问、模块设计、命名空间、自动加载、Traits引入、API友好配置目录、配置格式、配置加载、读取配置、动态配置、独立配置、路由模式...

    在线考试系统

    常见的技术栈包括HTML/CSS/JavaScript用于前端,而Java、Python、PHP等后端语言用于服务器端开发,数据库如MySQL、MongoDB存储数据。 10. **性能优化**:由于考试期间可能会有大量用户同时在线,因此系统需具备高...

    超好用的在线考试系统

    1. 考试创建:管理员可以创建各种类型的试题,包括选择题、填空题、判断题、问答题等,支持随机抽题、分组出卷,确保每次考试的试题组合不同。 2. 考试管理:系统可设置考试时间、次数限制、防作弊机制,如限制作答...

    ThinkPHP5.0完全开发手册-07171040.pdf

    手册包含了对安装、开发规范、目录结构、基础架构配置、生命周期、入口文件、URL访问、模块设计、命名空间、自动加载、引入API友好配置目录、配置格式、配置加载、读取配置、动态配置、独立配置、路由模式、路由定义...

    自开发考试系统

    6. **源码与工具**:标签中提到的“源码”意味着该压缩包可能包含了系统的源代码,这对于开发者来说是一份宝贵的资源,可以学习和参考其设计思想和实现方式。而“工具”可能指的是用于辅助开发或维护的软件工具,如...

    一个有点像样的考试系统

    本文将基于提供的标题“一个有点像样的考试系统”来深入探讨构建这样一个系统的关键知识点。 首先,我们需要明确一个像样的考试系统应该具备的基本功能。这通常包括: 1. **用户管理**:系统应能管理不同的用户...

    长网址在线缩短.zip

    为了防止冲突,可以对哈希结果进行一定的处理,如取前几位,或者通过映射表将哈希值映射到特定的字母数字组合。 #### 4. API设计 为了方便其他应用集成,长网址在线缩短服务通常提供RESTful API。常见的API接口...

    考试系统源码

    - **组卷逻辑**:随机或按预设规则组合试题,形成试卷。 - **考试管理**:设定考试时间、次数限制、开放时间等参数。 - **答题与提交**:用户在规定时间内完成答题并提交。 - **自动评分**:对选择题和判断题进行...

    ThinkPHP5.0手册.pdf

    在配置方面,ThinkPHP5.0提供了配置目录、配置格式、读取配置、动态配置、独立配置等的详细说明,以及路由模式、路由定义、批量注册变量规则、组合变量、路由参数、路由地址、资源路由、快捷路由、路由别名、路由...

    ThinkPHP5.0完全开发手册1

    9. **路由**:详细阐述路由机制,包括路由模式、路由定义、批量注册、变量规则、组合变量、路由参数、路由地址、资源路由、快捷路由、路由别名、路由分组、MISS路由、闭包支持和路由绑定。 10. **域名路由**:利用...

    ThinkPHP5.1完全开发手册.pdf

    - **URL访问**:介绍了如何通过URL访问项目中的不同资源。 - **模块设计**:说明了如何进行模块化设计,以适应大型项目的开发需求。 - **命名空间**:讲解了命名空间的概念及其在ThinkPHP中的应用。 - **容器和依赖...

    ThinkPHP5.0完全开发手册

    - **关联统计**:统计关联模型的数据数量。 - **聚合模型**:聚合多个模型的数据。 ##### 12. **视图** - **视图实例化**:创建视图对象。 - **模板引擎**:支持多种模板引擎。 - **模板赋值**:向模板传递数据。 ...

Global site tag (gtag.js) - Google Analytics