启动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