标签 mongodb 下的文章

让Lavarel Eloquent ORM 支持 mongodb数据库

Laravel 的 Eloquent ORM 提供了漂亮、简洁的 ActiveRecord 实现来和数据库的互动。 每个数据库表会和一个对应的「模型」互动。

组件说明

业务侧还在用PHP5.3,composer.json文件内容如下:

{
    "require": {
        "illuminate/database": "4.1.*",
        "jenssegers/mongodb": "1.3.*"
    }
}

实际安装的版本如下。

组件版本
illuminate/databasev4.1.30
jenssegers/laravel-mongodbv1.3.2

使用方式:

  1. 配置文件conf/database.php新增mongodb配置。

    <?php
    $database = array(
        'mongodb' => array(
            'driver'    => 'mongodb',
             'host'      => '100.98.173.13',
             'port'      => 5566,
             'database'  => 'bigdata',
         ),
    )
  2. 自动加载数据库,新增mongodb数据库类型。

    include conf/database.php;
    
    $capsule = new Capsule;
    
    // 支持mongodb数据库,如果name是mongodb,交给Jenssegers\Mongodb\Connection来处理
    $capsule->getDatabaseManager()->extend('mongodb', function($config)
    {
        return new Jenssegers\Mongodb\Connection($config);
    });
    
    foreach ($database[$env] as $name => $conf) {
        // 创建链接
        $capsule->addConnection($conf, $name);
    }
    
    // 设置全局静态可访问
    $capsule->setAsGlobal();
    
    // 启动Eloquent
    $capsule->bootEloquent();
  3. model继承Jenssegers\Mongodb\Model.

    <?php
    class UserModel extends Jenssegers\Mongodb\Model {
    
        /**
         * table
         *
         * @var string
         */
        protected $table = 'users';
    
        /**
         * connection
         *
         * @var string
         */
        protected $connection = 'mongodb';
    }

上面是按网上找到的资料配置的,然后跑起来后报PHP Fatal error: Call to a member function connection() on a non-object in /web/xxx/vendor/illuminate/database/Illuminate/Database/Eloquent/Model.php on line 2810的错误。

断点定位了半天,才解决掉问题,这里记录一下。

先看下2810行的代码是什么。

2808    public static function resolveConnection($connection = null)
2809    {
2810        return static::$resolver->connection($connection);
2811    }

注意这里用的是static::$resolver,关于php的static和self的区别可以参考这篇文章,这里不做过多描述。
php中self与static的区别

解决方法:

修改vendor\jenssegers\mongodb\src\Jenssegers\Mongodb\Model.php文件,注释下面这行代码。

protected static $resolver;

MongoDB跟PostgreSql的对比

最近把一个业务项目从MongoDB切换到了PostgreSql上。

下面是切换前后的效果。

  1. 存储大小

    MongoDB

    PostgreSql

    上图为MongoDB,下图为PostgreSql。

    因为MongoDB会把json的每个字段都做索引,所以它占用的空间要比PostgreSql大的多。

  2. web请求耗时

    MongoDB

    PostgreSql

    上图为MongoDB,下图为PostgreSql。

    MongoDB的平均耗时在10ms左右,PostgreSql的平均耗时在20ms左右。
    因为PostgreSql规划了表结构,每一次请求是要查多个表的,而MongoDB只需要查一个表。

PHP如何获取mongoDB查询的条数

有业务代码如下:

$conn = new MongoClient('mongodb://127.0.0.1:27017');
$db = $conn->database->table;

$start = 0;
$limit = 200;
while (1) {
    $conditions = array(
        'id' => array(
            '$gt' => $start,
        ),
    );
    $dataList = $db->find($conditions)->limit($limit);

    // 这里需要知道查询到最后,跳出while循环

    foreach ($dataList as $data) {
        // 业务处理代码
    }
}

- 阅读剩余部分 -

mongodb如何实现group by查询

查询命令用到了mongodb的管道命令。

命令如下:

db.table.aggregate([{$group : {_id : "$field", num_tutorial : {$sum : 1}}}])

$field 表示按field字段进行分组。
$sum 表示计算总和,默认值为1。

如果还需要按总和倒叙排列,命令如下:

db.table.aggregate([{$group : {_id : "$field", num_tutorial : {$sum : 1}}}, {$sort : {num_tutorial : -1}}])

记一次mongodb查询的问题

问题描述

同样的代码,重复执行后就会出现查询超时的错误。
代码类似如下:

$start = file_get_contents('start.pid');
if (!$start) {
    $start = 0;
}

$conditions = array(
    'id' => array(
        '$gt' => $start,
    ),
);

$conn = new MongoClient('mongodb://127.0.0.1:27017');
$dataList = $conn->db->table->find($conditions)->limit(10);

foreach ($dataList as $data) {
    // 具体逻辑
}

问题排查

看了explain的信息,没发现任何问题,想到mongo有提供shell操作。

执行以下命令

db.table.find({"id":{"$gt":"12998"}}).limit(1)

// 输出为空

执行以下命令

db.table.find({"id":{"$gt":12998}}).limit(1)

// 输出查询结果

对比上面两个命令,发现区别在于条件里的类型。
事后查了下资料,发现mongodb的字段类型必须一致。

资料参考:
为什么mongodb的字段会有类型之分