[MongoDB] Mongodb攻略
【基础】
1. 安装:
wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-rhel70-3.0.7.tgz tar zxvf mongodb-linux-x86_64-rhel70-3.0.7.tgz mv mongodb-linux-x86_64-rhel70-3.0.7.tgz mongodb rsync -a mongodb /usr/local # 复制到/usr/lcoal下 mkdir /usr/local/mongodb/data # 数据目录 touch /usr/local/mongodb/dblogs # 日志文件 ./usr/local/mongodb/bin/mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/dblogs --fork # 启动 pstree -p | grep mongod
启动命令常用参数选项说明:
--dbpath 指定数据库的目录
--port 指定数据库的端口,默认是27017
--bind_ip 绑定IP
--logpath 指定日志存放目录
--logappend 指定日志生成方式(追加/覆盖)
--pidfilepath 指定进程文件路径,如果不指定,将不产生进程文件
--keyFile 集群模式授权验证的私有key
--journal 启用日志
--nssize 指定.ns文件的大小,单位MB,默认是16M,最大是2G
--maxConns 最大的并非连接数
--notablescan 不允许进行表扫描
--noprealloc 关闭数据文件的预分配功能
--fork 以后台Daemon形式运行服务
更多的参数选项利用mongod --help 进行查看
启动时会显示或在日志里的4个Warning:
** WARNING: Readahead for /usr/local/mongodb is set to 4096KB
We suggest setting it to 256KB (512 sectors) or less
http://dochub.mongodb.org/core/readahead ** WARNING: You are running this process as the root user, which is not recommended. ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'. We suggest setting it to 'never' ** WARNING: /sys/kernel/mm/transparent_hugepage/defrag is 'always'. We suggest setting it to 'never'
① 参考官网提示:
保证对用来存储数据文件的块设备的预读设置是合适的。对于随机访问模式,设置低的预读值。一个预读值为32(16kb)通常工作的很好。
对于标准块设备,可以运行 sudo blockdev --report 得到预读值设置,运行 sudo blockdev --setra <value> <value> 改变预读值设置。
参考你的具体操作系统手册来了解更多信息。
其实运行了 blockdev --report 之后展示了几行信息,排除非4096的,但这样是不能确定哪个是用来存储数据文件的块设备。
用 df -h 查看文件系统信息,可以看到容量最大的就是我们的硬盘,就用它来存储数据文件吧。
运行 blockdev --setra 256 你的盘符名(如:/dev/sda2)。
② 第二个完全可以忽略。
③④ 按照建议设置,设置方式参考:
https://docs.mongodb.org/manual/tutorial/transparent-huge-pages/
https://oracle-base.com/articles/linux/configuring-huge-pages-for-oracle-on-linux-64#disabling-transparent-hugepages
我这里就直接把下面的加到rc.local的末尾,开机设置并自启:
# {{{ 去除Mongodb启动时Warning if [ -f /sys/kernel/mm/transparent_hugepage/enabled ]; then echo never > /sys/kernel/mm/transparent_hugepage/enabled fi if [ -f /sys/kernel/mm/transparent_hugepage/defrag ]; then echo never > /sys/kernel/mm/transparent_hugepage/defrag fi blockdev --setra 256 /dev/sda2 # }}} /usr/local/mongodb/bin/mongod --dbpath=/usr/local/mongodb/data --logpath=/usr/local/mongodb/dblogs --fork
如果当前手工改动后,验证是否由 [always] madvise never 变为 always madvise [never]
cat /sys/kernel/mm/transparent_hugepage/enabled
2. 进入客户端:
/usr/local/mongodb/bin/mongo,进入后默认创建并选择test数据库。
与关系型数据库的对应关系:
MySQL MongoDB
database(数据库) database(数据库)
table(表) collection(集合)
rows(记录) document(文档对象)
基础命令:
db 显示当前所在数据库
use test 选择test数据库,默认就在test库
show dbs 显示所有数据库
show collections 显示当前数据库的表
show tables (上面的别名)
db.ci.insert({name:'far', age:'18'}) 在test库的ci集合中插入一条数据
db.ci.find(); 查询ci集合所有数据
db.ci.find({条件}); 查询指定数据
db.ci.remove({name:"user1"}) 删除test数据库ci集合中的数据
db.ci.remove({}) 删除所有数据
db.ci.update({name:'far'}, {name:'fff'}); 修改查找到的数据,会将数据的其它字段清除
db.ci.update({name:'fff'}, {$set:{name:'wish'}}); 只修改当前查找到的字段,其余不变
批量插入:
条件查找:
db.ci.insert({name:'user10', age:30, sex:'nan'})
( 查询的魔术方式一般在内测,更新的魔术方法在外侧 )
条件表达式($gt, $gte, $lt, $lte, $ne, $in, $nin, $all, $mod, $exists, $or, $nor, $size, $elemMatch):
db.ci.find({age: {$gt: 5}}) 大于5的
db.ci.find({age: {$gte: 5}}) 大于等于5的
db.ci.find({age: {$lt: 5}}) 小于5的
db.ci.find({age: {$lte: 5}}) 小于等于5的
db.ci.find({age: 5}) 等于5的
db.ci.find({age: {$ne: 5}}) 不等于5的
db.ci.find({age: {$in: [1, 3, 5]}}) 在1,3,5中的,这里的中括号不是数组
db.ci.find({age: {$nin: [1, 3, 5]}}) 不在1, 3, 5中的
db.c2.insert({name: 'user1', post: [1,2,3,4,5]});
db.c2.find({post: {$all: [1,2,3]}}) 查询post里面包含数组123的,有一个不包含则不显示
取余($mod)
db.ci.find({age: {$mod: [2,1]}}) 这里的中括号是操作符,除2余1的行
db.ci.find({age: {$mod: [3,1]}}) 除3余1的行
db.ci.find({age: {$mod: [4,0]}}) 除4余0的行
检查一个字段是否存在($exists)
db.c2.find({ age: {$exists: 1}}) 查询c2里面是否有包含age字段的数据,有就返回此行
db.c2.find({name: {$exists: 1}})
db.c2.find({post: {$exists: 1}})
或者/除了($or/$nor),语法与其它的不一样
db.ci.find({$or: [{name:'user1'}, {age:8}]}) name为user1 或者 age为8的行
db.ci.find({$nor: [{name:'user1'}, {age:8}]}) 除了 name为user1 和 age为8的行
根据数组长度筛选($size)
db.c2.find({post: {$size: 5}}) 查询post数组长度为5的行
db.c2.find({post: {$size: 1}})
元素匹配($elemMathc)
db.c3.insert({name: 'user1', post: [{tit: 1}, {tit: 2}, {tit: 3}]})
db.c3.insert({name: 'user2', post: [{tit: 'aa'}, {tit: 'bb'}, {tit: 'cc'}]})
db.c3.find({'post.tit': 'aa'}) 支持字段间的点操作符
db.c3.find({post: {$elemMatch: {'tit': 'aa'}}}) 效果同上,$elemMatch表示匹配post下面的元素,这种用法可以避免上一种用法的点操作符在其它语言中可能引起的麻烦
正则:
db.c2.find({name:/ser1/i})
NULL查询:
db.c4.insert({name:'user1'});
db.c4.insert({name:'user2', age:10})
db.c4.insert({name:'user3', age:11})
db.c4.insert({name:'user4', age:null})
db.c4.find({age: {$exists: 1, $in: [null]}}) 先过滤掉没有age的,然后取null值的行
db.c4.find({age: {$type: 10}}) age类型为10的行,同上。(关于这个类型有很多种,每个都有对应的数字表示)
db.c4.find({age: {$type: 10}, {name: 'user3'}}) 逗号隔开,同时满足两个条件
$slice,取数组的一部分:
db.c3.find({name: 'user1'}, {post: {$slide: 2}}) 取post值的前两条
db.c3.find({name: 'user1'}, {post: {$slide: -2}}) 取post值的后两条
db.c3.find({name: 'user1'}, {post: {$slide: [2, 2]}}) 取post的值:跳过第2个取2个
数量,排序,限制:
db.ci.count() 统计数量,支持链式操作
db.ci.find().count()
db.ci.find().sort({name:1}) 升序排序
db.ci.find().sort({age:-1}) 降序排序
db.ci.find().skip(2).limit(3) 跳过2个显示3个
db.ci.find().sort({age:-1}).skip(2).limit(3) 即使sort放在后面也会先排序
db.ci.find().sort({age:-1}).skip(2).limit(3).count(0) count不传和传0,不包含find()后面的条件
db.ci.find().sort({age:-1}).skip(2).limit(3).count(1) count传1,包含find()后面的条件
Distinct,类似Sql中的distinct:
db.ci.distinct('name') 返回不唯一的name的值组成的数组
游标,类似Sql中的游标:
var x = db.ci.find()
x.hasNext() 只有在判断是否有下一条的时候才连接数据库
x.next() 取值
更新操作:
db.collection.update(criteria, objNew, upsert, multi)
criteria:用于设置查询条件的对象
objNew:用于设置更新内容的对象
upsert:如果记录已经存在,那么更新它,否则新增一条记录(0或1,默认给0最合适)
multi:如果多个符合条件的记录,全部更新;默认情况下,只会更新第一个符合条件的记录。(0或1,最好设为1全部跟新)
db.c4.update({name:'user4'}, {name:'user44'}, 1) 第三个参数设为1,那么前面的不存在,就插入新的objNew数据;如果存在,第三个参数0和1无所谓
db.c5.insert({name:'user1'})
db.c5.insert({name:'user1'})
db.c5.insert({name:'user1'})
db.c5.update({name:'user1'}, {name:'user11'}) 不加第四个参数,只更新第一条匹配的数据
db.c5.update({name:'user1'}, {name:'user11'}, 0, 1) 报错,multi update only works with $ operators,必须带$set
db.c5.update({name:'user11'}, {$set: {name:'user1'}}, 0, 1) 全部更改的正确方式,使用模式方法$set
db.c5.update({name:'user1'}, {$set : {age:10}}, 0, 1) 当要更改成的字段age不存在时,增加一个字段,类似Sql的set操作
$inc自增操作:
db.c5.insert({name: 'user1', scrore: 10})
db.c5.update({name: 'user1'}, {$set: {score: 5}}, 0, 1) 给user1的积分加5,score字段有则累加,没有则创建并累加;$set没有办法完成加减
db.c5.update({}, {$set: {score: 5}}, 0, 1) 给所有人积分加5
db.c5.update({name:'user1'}, {$inc: {score: -2}}, 0, 1)
$unset删除字段:
db.c5.update({}, {$unset: {score: 1, age: 1}}, 0, 1) 这里的1是为真的意思
$push对数组值新增元素:
db.c5.insert({name:'user2', arr:[1, 2, 3]})
db.c5.update({name:'user2'}, {$push: {arr: 4}}) 在arr字段的数组中新加一个元素
db.c5.update({name:'user2'}, {$push: {arr: [5, 6, 7]}}) 在arr字段的数组中新加一个子数组
db.c5.udpate({name:'user2'}, {$pop: {arr: 1}}) 把arr字段数组中最后一个元素弹出
db.c5.update({name:'user2'}, {$pushAll: {arr: [5, 6, 7]}}); 批量在arr字段的数组中新增元素,中括号是操作符,依次压入中括号里的三个数
Refer:使用Mongodb的利弊