MongoDB是目前一款比较流行的文档数据(document-oriented database), 类似的还有Apache CouchDB等。

安装

MongoDB安装非常简单,在http://www.mongodb.org下载对应版本(如Linux 32bit/64bit),解压即可。

PHP需要安装Mongo扩展(MongoDB driver for PHP),通过pecl或在http://pecl.php.net/package/mongo下载编译即可。

MongoDB服务启动/停止

例如:

./mongod --port 10001 \
--logpath=/var/logs/mongodb/mongod.log \
--dbpath=/var/data/db/ \
--pidfilepath /var/run/mongod.pid \
--directoryperdb

很多其它参数参考:

./mongod --help | less

停止服务,直接Ctrl+C或者kill `cat /var/run/mongod.pid`即可。

另外先提一下MongoDB提供的Shell客户端:./mongo, 很多操作需要使用它,例如数据管理配置等。

./mongo

默认连接到localhost:27017/test

./mongo 192.168.0.33:10001/blog

连接到192.168.0.33的服务器,端口为10001, 并使用blog数据库.

database与collection

MongoDB是free-schema数据库,所以文档结构不需要像关系型数据库一样严格定义,也没有类似create database, create table, alter table等之类的操作。

例如下面命令将工作数据库切换到blog,但blog并不需要预先create.

> use blog

对于collection也是类似,不需要预先创建, 下面命令将文档插入名为posts的collection.

> db.posts.insert({"title":"Hello, MongoDB", "date":new Date()}) 

Collection类似于关系型数据库的表.

注意到这里插入的简单文档看起来是一个JSON。MongoDB存储文档的格式正是JSON,不过是Binary JSON,所要又称为BSON.

PHP访问数据库

详细文档请参考:PHP:Mongo, 下面例举简单示例。

连接数据库

$mongo = new Mongo("192.168.0.33:10001");

选择数据库

//use database blog
$blog = $mongo->blog;

选择Collection:

//collection posts
$posts = $blog->posts;

写入数据

$post = array(
    'title'=>'Hello, MongoDB',
    'content'=>'

Great MongoDB

', 'date'=>new MongoDate(/*default=time()*/), 'views' => 0 ); //insert one document $posts->insert($post); $post2 = array( 'title' => 'Powerfull mongoDB', 'content' => '

Powerfull, mongoDB

', 'author' => 'James Tang', 'date' => new MongoDate(/*time()*/), 'views' => 0 ); //insert multiple documents $posts->batchInsert(array($post, $post2));

写入操作可以有可选参数, 如:

$posts->batchInsert(array($post, $post2),array(
    'safe'=> true
));

‘safe’=>true 表示等待数据库响应再返回,如果写入失败则抛出MongoCursorException异常,其它参数参考文档。

更新

//Query one document
$post = $posts->findOne(array('title' => 'Hello, MongoDB'));

if ($post) {
        $post['title'] = 'Hello, mongoDB 2';

        //update
        $posts->update(array('_id'=> $post['_id']), $post);
}

Upsert, 即更新或者新增加:

//use 'upsert' option of update() method
$posts->update(array('title'=> $post['title']), $post, array(
   'upsert'=>true,
));

//use save() method, more convenient
$posts->save($post);

MongoDB提供了更新操作符,如$inc, $set, $push, …

//$inc modifier, value of `views` field will increase one.
$posts->update(array('_id'=> $post['_id']), array(
        '$inc' => array('views'=>1)
));

//$set modifier, set the value of `views` to 0
$posts->update(array('_id'=> $post['_id']), array(
        '$set' => array('views'=>0)
));


//$push adds an element to the end of an array 
//if the specified key already exists and
//creates a new array if it does not.
//a new field `tags` will be added for our example
//and has one element `php` 
$posts->update(array('_id'=> $post['_id']), array(
        '$push' => array('tags'=>'php')
));

更多关于更新与操作符的信息,请参考:Updating

删除:

$posts->remove(array(
        'title' => 'Hello, mongoDB'     
));

//remove all document in the collections
$posts->remove();

//more efficient than remove()
$posts->drop();

简单查询:

//query one document
$posts->findOne(/*criteria*/);

//a cursor of documents
$posts->find(/*criteria*/);

示例:

//query the document with title contains "mongoDB", case insensitive, 
//and only return the title, date fields.
$cursor = $posts->find(array(
        'title' => new MongoRegex('/mongoDB/i'),
),array(
        '_id'=>false,
        'title',
        'date'
));

//sorting document
$cursor->sort(array(
        'title' => -1, //1-ascending, -1 descending     
));

//limit in 3 document
$cursor->limit(3);

foreach ($cursor as $post) {
        echo $post['title'] . "\n"; 
        echo date('Y-m-d', $post['date']->sec) . "\n";
}

参考:http://www.mongodb.org/display/DOCS/Querying

“_id”与ObjectId

每一个Document都有一个_id属性,每个文档的_id必须唯一,如果创建文档时没有指定,Mongo客户端会自动生成一个_id,其值为ObjectId类型,在PHP中对应的类为MongoId.

“_id”也可以是其它类型,如Int, string,但不能是array。

ObjectId以12字节存储,其生成方法如下:

1 2 3 4 5 6 7 8 9 10 11
Timestamp Machine PID Increment
  • Timestamp精确到秒,如1320978110
  • Machine为hostname, 或者Mac/网络地址, 或者虚拟机ID的MD5序列的前三字节
  • Increment,类似于自增,所以在新增多个文档时可能这几位是连续的,但也可能是随机数

除了timestamp可以确定外,后面三部分可能会因客户端不同而生成方式有点差异。

例如ObjectId(“4ebc86bedf8a426362118b5d”),这是ObjectID的表示,4ebc86be对应1320978110。

但ObjectID之所以表示为24个字符的字符串,是因为第个字节以两个十六进制数表示。

总结

MongoDB更适合面向对象编程,free-schema能够更加敏捷地就会需求变化。其它高级特性及应用需要进一步学习。