PHP操作MongoDB

MongoDB 是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。他支持的数据结构非常松散,是类似json的bson格式,因此可以存储比较复杂的数据类型。Mongo最大的特点是他支持的查询语言非常强大,其语法有点类似于面向对象的查询语言,几乎可以实现类似关系数据库单表查询的绝大部分功能,而且还支持对数据建立索引。 ————引自百度百科

MongoDB现在应该是当下比较流行的新兴的数据库了,我工作中的使用是从去年开始的,由于业务需要存放大量的json格式的数据,而且数据量也很大,数据结构也有可能会有很大的出入,所以选择了mongo这个数据存储工具,在实际开发中遇到了很多问题,故做了一次整理。 本文中所使用的PHP扩展是原生的扩展,而非其他的经过二次封装的扩展。使用的时候请注意。

基本操作

最基本的操作就是insert,find,update,delete这些个操作了,

insert

insert主要包含insertMany和insertOne这个两个方法,insertOne只能添加一个文档到集合中,insertMany可以以一个数组的形式插入多个文档到集合中,当然如果你可以确定唯一的主键,文档的主键是可以自己定义的在自己的数组中直接定义_id就可以了。

// PHP CODE

$mongo = Mongo::client($mongo['host'])->selectCollection($mongo['database'], 'first');
//插入一个文档到集合中
$service_data = [
'_id' =>1,
'service_id' =>'csuid',
'mode' => 0,
];
$mongo->insertOne($service_data);
//插入多个文档到集合中
$service_data = [
[
'service_id' => 'csuid',
'mode' => 0,
],
[
'service_id' => 'csuid',
'mode' => 0,
],
];
$mongo->insertMany($service_data);

其实在这儿是没有返回结果的,如果你直接将上面的方法运行结果返回的话,他将返回[]这样的结果。如果你要看他的插入的_id你可以查看$res->getInsertedIds()或者使用$res->getInsertedId()方法查看添加的_id。insert方法大概就只有这些使用技巧。

find

find要说的东西也不是特别的多需要注意的大概就是一些,不等于,大于,小于,in,not in等查询条件及option方法的使用。
主要的查询条件我做个列表记录一下
1. > => $gt
2. < => $lt
3. >= => $gte
4. <= => $lte
5. <> => $ne
6. in => $in
7. not in => $nin
除了这些个查询条件,还有一个重要的就是option,其实对于mongo for php来说剩下的排序,分页都是在option中完成的,当然还有类似SQL中的select也是在option。如果你需要查询出什么字段就写在option这个参数中,这个是为了减少查询量的最好方式。

// PHP CODE

$filter = [
'tid' => $this->query['tid'],
'type' => 4,
'disable' => 1,
'time' => time(),
'sid' => ['$in' => $sid_arr],
];
$option = [
'projection' => [
'ctime' => 1,
'_id' => 1,
'sid' => 1,
'tid' => 1,
'quotation3rd.read' => 1,
],
'sort' => [
'ctime' => -1,
],
’skip‘=>1,
'limit'=>2,
];
var_dump($mongo->find($filter, $option)->toArray());

这样查询出来的mongo还是一个对象,如果需要转为数组可以使用iterator_to_array这个方法,这样处理后_id还会是一个对象,这儿需要对_id做string的转化。

update

update主要的操作就和SQL的更新类似,但是还有一些其他的操作,还是列一个列表来说一下吧。
* 更新 => $set
* 删除字段 => $unset
* 在数组中添加一个不考虑重复值 => $push
* 在原有的数组基础上添加多个值 => $addToSet &$each
* 删除数组的第一个或者最后一个值=> $pop
* 删除数组中匹配的元素 => $pull
基本有这么多的使用方法,我只举一个我用到的例子

// PHP CODE

$verify_list = [
[
'service_id' => 'csuid',
'mode' => 1,
],
[
'service_id' => 'csuid',
'mode' => 2,
],
[
'service_id' => 'csuid',
'mode' => 3,
],
[
'service_id' => 'csuid',
'mode' => 4,
],
[
'service_id' => 'csuid',
'mode' => 4,
],
];
$update_verify['data'] = ['$each' => $verify_list];
$mongo->updateOne(['id'=>'syc'], ['$addToSet' => $update]);

delete

这个没什么好说的吧,就是找到匹配的数据,进行删除删除操作,不过分为deleteOne和deleteMany这两个方法,

// PHP CODE

$mongo->deleteOne(['id'=>'syc']);

聚合

聚合我觉的是一个比较复杂的结构,当然除了count,count就是查出总条数,主要比较复杂的是aggregate,

count

count就是这么简单粗暴直接,

// PHP CODE

$mongo->count(['id'=>'syc']);

aggregate

aggregate是一个重要的聚合方法,目前我用到的主要就是分组,这个还是分组的方法还是需要去自己拼接很多参数和逻辑的,重要的参数

  1. 筛选的条件 => $match
  2. 分组要显示的字段 => $group
  3. 排序 => $sort
  4. 分页 => $skip & $limit

这里需要注意的是除了分页的参数外其他的几个参数都是需要一个对象的,group中的字段要使用mongo中字段时需要在前面带上”$”

// PHP CODE

//分组分页查询值
$filter = [
[
'$match' => [
'date' => ['$gte' => time()],
'type' => ['$nin' => ['server', 'order']],
'cmuid' => ['$in' => ['1','2','3']],
'csuid' => ['$in' => ['2','3','4']],
],
],
[
'$group' => [
'_id' => [
'csuid' => '$csuid',
'cmuid' => '$cmuid',
],
'date' => ['$sum' => 1],
'start_Time' => ['$min' => '$date'],
'recent_Time' => ['$max' => '$date'],
],
],
[
'$sort' => ['start_Time' => -1],
],
[
'$skip' => 15 * 1,
],
[
'$limit' => 15,
],
];
// 在这儿要将useCursor设置为false,否则的话返回的是一个Cursor对象
$mongo->aggregate($filter, ['useCursor' => false]);
//查询总数量
$filter_count = [
[
'$match' => [
'date' => ['$gte' => time()],
'type' => ['$nin' => ['server', 'order']],
'cmuid' => ['$in' => ['1','2','3']],
'csuid' => ['$in' => ['2','3','4']],
],
],
[
'$group' => [
'_id' => [
'csuid' => '$csuid',
'cmuid' => '$cmuid',
],
'sum' => ['$sum' => 1],
'time' => ['$min' => '$date'],
'times' => ['$max' => '$date'],
'count' => ['$avg' => ['$sum' => 1]],
],
],
[
'$group' => [
'_id' => null,
'count' => [
'$sum' => 1,
],
],
],
];
$mongo->aggregate($filter, ['useCursor' => false]);

在aggregate中是无法直接记录出总数量的count方法的,***只能去取巧,使用两个group和$sum计算分组后的总条数,对于mongodb/mongodb这个组件来说是没有group这个方法的。***