启动mongo命令:
sudo /usr/local/opt/mongodb/bin/mongod --dbpath /data/db/ --logpath=/var/log/mongodb.log --logappend &
假定mongo有一个表结构如下:
_id MongoId id sub_id int 原来sql表中的信息id title string 信息内容 img_path string 图片路径 img_width int 图片宽 img_height int 图片高 love int 被喜欢的次数 review int 评论数 src_status int 魔信来源,主平台、手机等 nat_status int 魔信分类,图片、视频等 status int 是否删除 access_status int 访问权限 access_data array 当access_status=4时,指定谁能访问 can_fans array 谁能查看 cant_fans array 谁不能查看 t_sub_id int 转发id t_sub_id2 int 转发id mx_id int 谁发的 browse int 已看过总数 cby int 创建时间 love_data array 喜欢人的id数组 click int 查看人的数量 click_data array 查看人的id数组 review_data array 评论数组 id MongoId 评论id,在评论表中的MongoId v_mx_id int 谁评论的 content string 内容 cby int 时间 yo array 所有yo过的人的id数组 browse_data array 所有已看的人的id数组 forward_data array 所有转发人的id数组 shield_data array 所有屏蔽该魔信的用户id数组,将id作为key值
如果access_status可能值为0-3,现在我要查access_status为0-2时mx_id指定范围,为3时mx_id不能为指定值(不能为自己):
{ '$or':[ {'$and':[{'$in':{'t_type':[0,1,2]}}, {'$in':{'mx_id':[34,52]}}]}, {'$or':[{'t_type':3}, {'mx_id':{'$ne':34}}]} ] }
转化成php数组形式就为:
array( '$or'=>array( array( '$and'=>array( array( '$in'=>array('t_type'=>array(0,1,2))) ,array( '$in'=>array('mx_id'=>array(34,52))))), array( '$or'=> array( array('t_type'=>3) ,array('mx_id'=>array('$ne'=>34)))) ) )
我要查t_sub_id值类型为MongoId的:
{ 't_sub_id':{'$type':7} }
常用$type值见官网地址:http://www.mongodb.org/display/DOCS/Advanced+Queries
查询:
{'love':6} //love=6 {'love':{'$ne':6}} //love!=6 {'love':{'$gt':6}} //love数大于6 $lt:小于 $gte,$lte >= , <= {'access_status':{'$in':[0,1,2]}} //access_status=0或1或2 {'browse_data':{'$all':[1,2,3]}} //browse_data中必须要有1,2,3三个值 {'shield_data.1642':{'$exists':true}} //shield_data数据下面存在1642的key {'review_data':{'$size':5}} //review_data数组长度为5 {'$where':'this.review_data.length > 6'} //review_data数组长度大于6,这样会比较慢,一般设置一个字段review_len表示review长度,然后查review_len>6 {'title':/my god/} //正则匹配
修改:
db.info.update({'_id':ObjectId('xxxxx')}, {'$inc':{'love':1}} ); //将love数+1 db.info.update({'mx_id':1002, 'status':0}, {'$set':{'status':1}}); //将mx_id=1002且status=0的记录,修改status=1 db.info.update({'_id':ObjectId('xxxxx')}, {'$push':{'shield_data':{1088:1}}}); //将array(1088=>1)的值添加到数组shield_data最后 db.info.update({'_id':ObjectId('xxxxx')}, {'$pop':{'review_data':-1}}; //删除到review_data数组的第一个元素,1为删除最后一个元素 db.info.update({'_id':ObjectId('xxxxx')}, {'$pull':{'forward_data':1321}}); //删除forward_data数组中所有值为1321的元素 db.info.update({'movie_info':{'$exists':true}}, {'$rename': {'movie_info':'mov_info'}}) //将movie_info字段改名为mov_info
shell命令:
show dbs; #显示所有数据库 use info; #切换到info库 show collections; #显示info库所有聚集 db.info.findOne(); #info库下面sub_info表找一条 db.getPrevError(); #返回之前操作的错误 db.info.find().forEach( function(x) { print(tojson(x));}); #forEach用法 var cursor = db.info.find(); print (tojson(cursor[4])); #cursor当数组用 db.currentOp(); #获取当前正在执行的操作。 db.serverStatus(); #获取服务器的状态 db.stat(); #获取当前数据库的信息,比如Obj总数、数据库总大小、平均Obj大小等 /usr/local/opt/mongodb/bin/mongodump --db sys_info --collection info #导出sys_info库下面的info集合 /usr/local/opt/mongodb/bin/mongorestore -h 127.0.0.1 #从刚的备份中恢复
将click_log表里面的id0字段为string类型的,转换成int:
db.click_log.find( { 'id0' : { $type : 2 } } ).forEach( function (x) { x.id0 = new NumberInt(x.id0); db.click_log.save(x); });
mongostat是mongdb自带的状态检测工具,在命令行下使用。它会间隔固定时间获取mongodb的当前运行状态,并输出。如果你发现数据库突然变慢或者有其他问题的话,你第一手的操作就考虑采用mongostat来查看mongo的状态。
它的输出有以下几列:
inserts/s 每秒插入次数 query/s 每秒查询次数 update/s 每秒更新次数 delete/s 每秒删除次数 getmore/s 每秒执行getmore次数 command/s 每秒的命令数,比以上插入、查找、更新、删除的综合还多,还统计了别的命令 flushs/s 每秒执行fsync将数据写入硬盘的次数。 mapped/s 所有的被mmap的数据量,单位是MB, vsize 虚拟内存使用量,单位MB res 物理内存使用量,单位MB faults/s 每秒访问失败数(只有Linux有),数据被交换出物理内存,放到swap。不要超过100,否则就是机器内存太小,造成频繁swap写入。此时要升级内存或者扩展 locked % 被锁的时间百分比,尽量控制在50%以下吧 idx miss % 索引不命中所占百分比。如果太高的话就要考虑索引是不是少了 q t|r|w 当Mongodb接收到太多的命令而数据库被锁住无法执行完成,它会将命令加入队列。这一栏显示了总共、读、写3个队列的长度,都为0的话表示mongo毫无压力。高并发时,一般队列值会升高。 conn 当前连接数 time 时间戳
类似于mysql的phpmyadmin一样的管理工具,mongo有一个叫rockmongo。配置rockmongo有时候,注意如果是配置mongo群集,则要加如下参数:
$MONGO["servers"][$i]["mongo_options"] = array('replicaSet' => 'REPLICA_NAME');//mongo server name $MONGO["servers"][$i]["mongo_host"] = "mongodb://192.168.0.2,192.168.0.3";//mongo host $MONGO["servers"][$i]["mongo_port"] = false;//mongo port
SQL:
select sum(app_num) as cot,mx_id from table group by mx_id;
用mongo实现为:
db.table.group( {key: { mx_id:true }, reduce: function(obj,prev) { prev.cot += obj.app_num; }, initial: { cot: 0 } });
update 时,如果要修改多条记录,则要设置multiple选项,如:
odb::mongodb()->insert(otable::DB_MSG, otable::TABLE_MSG_USER_SYSTEM, $new_system_msg); $mongo_id = $new_system_msg['_id']; $options = array('multiple'=>true); odb::mongodb()->update(otable::DB_MSG,otable::TABLE_MSG_USER_FEEDS,array(),array('$push'=>array('msg_system'=>$mongo_id)),$options);
update时,如果该记录不存在,则插入一条记录,用upsert=true选项。如修改 info的值为3,如果info字段不存在,则插入。
db.info.update({'_id':ObjectId('xxxxx')}, {'$addToSet':{'shield_data':1088}}}); //向shield_data中插入唯一记录,如果不存在,才插入此记录
使用 db.collection.find() 返回数据,每一条占一整行,一点格式都没有,好难阅读,不知道有没有方法格式化返回的值,比如每个key-value占一行这种的。
db.collection.find().pretty();
补充个一劳永逸的方法,在 shell 里执行下列代码
echo “DBQuery.prototype._prettyShell = true” >> ~/.mongorc.js
这样随时随地都是 pretty() 了
现在我要从TABLE_INFO_CLICK表中查询所有click记录,对指定mx_id,只取时间字段cby最大的一条,可以用mongo函数来实现:
$keys = array("mx_id"=>true); // 要显示的栏位 $initial = array("mx_id" => 0); // 使用js將要显示栏位的值塞入 prev.mx_id = obj.mx_id; $reduce = 'function (obj, prev) { if(!prev[obj.mx_id] || prev[obj.mx_id] < obj.cby) { prev[obj.mx_id] = obj.cby; } delete(prev.mx_id); }'; $click_mx_ids = odb::mongodb()->group(otable::DB_INFO, otable::TABLE_INFO_CLICK,$keys,$initial,$reduce,array('sub_id'=>new MongoId($sub_id)));
但是这样效率非常低下,建议还是用mongo直接全部查出来,然后再用php处理。
_id MongoId id review_data array 评论数组 id MongoId 评论id,在评论表中的MongoId v_mx_id int 谁评论的 content string 内容 cby int 时间 yo array 所有yo过的人的id数组
上述结构中,向指定记录的review_data数组字段,字段中指定id值的一个元素,在其下面插入一个yo值:
db.info.update({'_id':ObjectId('xxxxx'), 'review_data.id':ObjectId('xxxxx')}, {'$push':{'review_data.$.yo':1088}});
来一个复杂查询:
$access_query = array(); $access_query['access_status'] = array('$in'=>array(0,2)); $access_query['mx_id'] = $mx_id; //是自己 $access_query['$and'] = array( array('access_status'=>4), array('access_data.cant_fans'=>array('$nin'=>array($mx_id))), //一定得不在禁止列表里面 array('$or'=>array(array('access_data.can_fans'=>array()),array('access_data.can_fans'=>array('$in'=>array($mx_id))))) ); $query = array( //访问权限 0公开 1仅魔友 2仅魔友和魔粉 3仅自己 4自定义 'status'=>0, //状态正常 'mx_id'=>array('$in'=>$arr), //是我关注的人 "shield_data.$mx_id"=>array('$exists'=>false), //我没有屏蔽这条魔信 '$or'=>array( //权限设置 array('access_status'=>$access_query['access_status']), //公开与魔友和魔粉 array('mx_id'=>$access_query['mx_id']), //仅自己,如果是自己的魔信,肯定可以见 array('$and'=> $access_query['$and']), //access_status=4 指定可见条件时 array('$and'=>array(array('access_status'=>1),array('mx_id'=>array('$in'=>$all_moyou)))), //仅魔友可见 ) );
换成js:
{ "$or": [ { "access_status": { "$in": [ 0, 2 ] } }, { "mx_id": 648 }, { "$and": [ { "access_status": 4 }, { "access_data.cant_fans": { "$nin": [ 648 ] } }, { "$or": [ { "access_data.can_fans": [] }, { "access_data.can_fans": { "$in": [ 648 ] } } ] } ] }, { "$and": [ { "access_status": 1 }, { "mx_id": { "$in": [ 743, 887845 ] } } ] } ], "mx_id": { "$in": [ 1, 64, 78, 113, 121, 124, 157, 249, 743, 754, 1000, 457, 79, 1131, 790, 887845, 602, 22, 887896, 648 ] }, "shield_data.648": { "$exists": false }, "status": 0 }
php的mongo采用正则表达式:
$regexObj = new MongoRegex("/^86-*/"); $find_condition = array('mx_tel'=>$regexObj); #http://php.net/manual/en/class.mongoregex.php
执行mongo类的时候,报如下notice:
( ! ) Notice: Mongo::__construct(): parsing servers
这个notice是由mongo的驱动输出的,可由下面代码关掉:
MongoLog::setLevel(MongoLog::NONE)
详见:http://stackoverflow.com/questions/11380822/php-mongo-notice-mongo-construct-parsing-servers