MongoDB

MongoDB

MongoDB简介

MongoDB 是由C++语言编写的,是一个基于分布式文件存储的开源数据库系统。

  1. 在高负载的情况下,添加更多的节点,可以保证服务器性能。
  2. MongoDB 旨在为WEB应用提供可扩展的高性能数据存储解决方案。
  3. MongoDB 将数据存储为一个文档,数据结构由键值(key=>value)对组成。MongoDB 文档类似于 JSON对象。字段值可以包含其他文档,数组及文档数组。

主要特点

NoSQL

NoSQL(NoSQL = Not Only SQL ),意即"不仅仅是SQL"。
NoSQL,指的是非关系型的数据库。NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

安装

下载

Windows

G:
md \data\db

启动mongod,指定数据文件路径
mongod --dbpath G:\MongoDB\db

启动mongod,指定配置文件(自己编写)
mongod --config G:\MongoDB\MongoDB.conf

启动mongo客户端
mongo

mongod参数

基本配置

选项 功能
--quiet # 安静输出
--port arg # 指定服务端口号,默认端口27017
--bind_ip arg # 绑定服务IP,若绑定127.0.0.1,则只能本机访问,不指定默认本地所有IP
--logpath arg # 指定MongoDB日志文件,注意是指定文件不是目录
--logappend # 使用追加的方式写日志
--pidfilepath arg # PID File 的完整路径,如果没有设置,则没有PID文件
--keyFile arg # 集群的私钥的完整路径,只对于Replica Set 架构有效
--unixSocketPrefix arg # UNIX域套接字替代目录,(默认为 /tmp)
--fork # 以守护进程的方式运行MongoDB,创建服务器进程
--auth # 启用验证
--cpu # 定期显示CPU的CPU利用率和iowait
--dbpath arg # 指定数据库路径
--diaglog arg # diaglog选项 0=off 1=W 2=R 3=both 7=W+some reads
--directoryperdb # 设置每个数据库将被保存在一个单独的目录
--journal # 启用日志选项,MongoDB的数据操作将会写入到journal文件夹的文件里
--journalOptions arg # 启用日志诊断选项
--ipv6 # 启用IPv6选项
--jsonp # 允许JSONP形式通过HTTP访问(有安全影响)
--maxConns arg # 最大同时连接数 默认2000
--noauth # 不启用验证
--nohttpinterface # 关闭http接口,默认关闭27018端口访问
--noprealloc # 禁用数据文件预分配(往往影响性能)
--noscripting # 禁用脚本引擎
--notablescan # 不允许表扫描
--nounixsocket # 禁用Unix套接字监听
--nssize arg (=16) # 设置信数据库.ns文件大小(MB)
--objcheck # 在收到客户数据,检查的有效性,
--profile arg # 档案参数 0=off 1=slow, 2=all
--quota # 限制每个数据库的文件数,设置默认为8
--quotaFiles arg # number of files allower per db, requires --quota
--rest # 开启简单的rest API
--repair # 修复所有数据库run repair on all dbs
--repairpath arg # 修复库生成的文件的目录,默认为目录名称dbpath
--slowms arg (=100) # value of slow for profile and console log
--smallfiles # 使用较小的默认文件
--syncdelay arg (=60) # 数据写入磁盘的时间秒数(0=never,不推荐)
--sysinfo # 打印一些诊断系统信息
--upgrade # 如果需要升级数据库

Replicaton 参数

选项 功能
--fastsync # 从一个dbpath里启用从库复制服务,该dbpath的数据库是主库的快照,可用于快速启用同步
--autoresync # 如果从库与主库同步数据差得多,自动重新同步,
--oplogSize arg # 设置oplog的大小(MB)

主/从参数

选项 功能
--master # 主库模式
--slave # 从库模式
--source arg # 从库 端口号
--only arg # 指定单一的数据库复制
--slavedelay arg # 设置从库同步主库的延迟时间

Replica set(副本集)选项:

选项 功能
--replSet arg # 设置副本集名称

Sharding(分片)选项

选项 功能
--configsvr # 声明这是一个集群的config服务,默认端口27019,默认目录/data/configdb
--shardsvr # 声明这是一个集群的分片,默认端口27018
--noMoveParanoia # 关闭偏执为moveChunk数据保存

上述参数都可以写入 mongod.conf 配置文档里例如:

dbpath = /data/mongodb
logpath = /data/mongodb/mongodb.log
logappend = true
port = 27017
fork = true
auth = true

也可以当启动参数,如:

./mongod -shardsvr -replSet shard1 -port 16161 -dbpath /data/mongodb/data/shard1a -oplogSize 100 -logpath /data/mongodb/logs/shard1a.log -logappend -fork -rest

权限管理常用命令

    1. #进入数据库admin
    use admin
    // use <db> 命令可以用于创建数据库,db.<db>.insert({"name":"菜鸟教程"})之后才会真正创建数据库

    2. #增加或修改用户密码
    //db.addUser('name','pwd')    #V3版本mongoDB已经不再使用addUser,而是采用了db.createUser
    db.createUser(
       {
         user: "name",
         pwd: "pwd",
         roles: [ "readWrite", "dbAdmin" ]
       }
    )

    3. #查看用户列表
    db.system.users.find()

    4. #用户认证
    db.auth('name','pwd')
    这一个返回1就认证成功了,只有认证成功才能对数据库进行操作

    5. #删除用户
    //db.removeUser('name')   #已过时
    db.dropUser('accountUser')

    6. #查看所有用户
    show users

    7. #查看所有数据库
    show dbs

    7.查看当前数据库
    db

    8. #查看所有的collection
    show collections

    9. #查看各collection的状态
    db.printCollectionStats()

    10. #查看主从复制状态
    db.printReplicationInfo()

二、使用mongodb

1.常用的命令

show dbs    显示数据库列表
use dbname    进入dbname数据库,大小写敏感,没有这个数据库也不要紧
show collections    显示数据库中的集合,相当于表格

2.创建&新增

db.users.save({"name":"lecaf"})    创建了名为users的集合,并新增了一条{"name":"lecaf"}的数据
db.users.insert({"name":"ghost", "age":10})    在users集合中插入一条新数据,,如果没有users这个集合,mongodb会自动创建
save()和insert()也存在着些许区别:若新增的数据主键已经存在,insert()会不做操作并提示错误,而save() 则更改原来的内容为新内容。
存在数据:{ _id : 1, " name " : " n1 "} ,_id是主键
insert({ _id : 1, " name " : " n2 " })    会提示错误
save({ _id : 1, " name " : " n2 " })     会把 n1 改为  n2 ,有update的作用。

3.删除

db.users.remove()    删除users集合下所有数据
db.users.remove({"name": "lecaf"})    删除users集合下name=lecaf的数据
db.users.drop()或db.runCommand({"drop","users"})    删除集合users
db.runCommand({"dropDatabase": 1})    删除当前数据库
db.dropDatabase()    删除当前数据库

4.查找

db.users.find()    查找users集合中所有数据
db.users.findOne()    查找users集合中的第一条数据

5.修改

db.users.update({"name":"lecaf"}, {"age":10})    修改name=lecaf的数据为age=10,第一个参数是查找条件,第二个参数是修改内容,除了主键,其他内容会被第二个参数的内容替换,主键不能修改

三、高级应用

1.条件查找

db.collection.find({ "key" : value })    查找key=value的数据
db.collection.find({ "key" : { $gt: value } })    key > value
db.collection.find({ "key" : { $lt: value } })    key < value
db.collection.find({ "key" : { $gte: value } })    key >= value
db.collection.find({ "key" : { $lte: value } })    key <= value
db.collection.find({ "key" : { $gt: value1 , $lt: value2 } })    value1 < key <value2
db.collection.find({ "key" : { $ne: value } })    key <> value
db.collection.find({ "key" : { $mod : [ 10 , 1 ] } })    取模运算,条件相当于key % 10 == 1 即key除以10余数为1的
db.collection.find({ "key" : { $nin: [ 1, 2, 3 ] } })    不属于,条件相当于key的值不属于[ 1, 2, 3 ]中任何一个
db.collection.find({ "key" : { $in: [ 1, 2, 3 ] } })    属于,条件相当于key等于[ 1, 2, 3 ]中任何一个
db.collection.find({ "key" : { $size: 1 } })    $size 数量、尺寸,条件相当于key的值的数量是1(key必须是数组,一个值的情况不能算是数量为1的数组)
db.collection.find({ "key" : { $exists : true|false } })    $exists 字段存在,true返回存在字段key的数据,false返回不存在字度key的数据
db.collection.find({ "key": /^val.*val$/i })    正则,类似like;“i”忽略大小写,“m”支持多行
db.collection.find({ $or : [{a : 1}, {b : 2} ] })    $or或 (注意:MongoDB 1.5.3后版本可用),符合条件a=1的或者符合条件b=2的数据都会查询出来
db.collection.find({ "key": value , $or : [{ a : 1 } , { b : 2 }] })    符合条件key=value ,同时符合其他两个条件中任意一个的数据
db.collection.find({ "key.subkey" :value })    内嵌对象中的值匹配,注意:"key.subkey"必须加引号
db.collection.find({ "key": { $not : /^val.*val$/i } })    这是一个与其他查询条件组合使用的操作符,不会单独使用。上述查询条件得到的结果集加上$not之后就能获得相反的集合。

指定返回那些列(键):
db.users.find({}, {‘name’ : 1, ‘skills’ : 1});
补充说明: 第一个{} 放where条件 第二个{} 指定那些列显示和不显示 (0表示不显示 1表示显示)
_id默认设置是1,所有也返回回来,可以设置_id不返回,例子:
      >db.orders.find({},{"onumber":1,"cname":1,"_id":0})

2.排序

db.collection.find().sort({ "key1" : -1 ,"key2" : 1 })    这里的1代表升序,-1代表降序

3.其他

db.collection.find().limit(5)    控制返回结果数量,如果参数是0,则当作没有约束,limit()将不起作用
db.collection.find().skip(5)    控制返回结果跳过多少数量,如果参数是0,则当作没有约束,skip()将不起作用,或者说跳过了0条
db.collection.find().skip(5).limit(5)    可用来做分页,跳过5条数据再取5条数据
db.collection.find().count(true)    count()返回结果集的条数
db.collection.find().skip(5).limit(5).count(true)    在加入skip()和limit()这两个操作时,要获得实际返回的结果数,需要一个参数true,否则返回的是符合查询条件的结果总数

MongoDB find方法

源数据

{  "uuid" : 12700004,  "card" : 981.3000000000029,
    "weixin" : {
        "unionId" : "o1wS90l6kHDFXY2lAPDb9bPxRZxI1",
        "openId" : "o9zCJ1Aat93B0UjdlCFDAWmimBcEb",
        "nick" : "麦袋",
        "sex" : 1,
        "avatar" : "http://thirdwx.qlogo.cn/mmopen/vi_32/DYAIOgq83eoNcMa5gLGs9iaTYCmNqycSk5XUWzKDVfj6sPkk1Oia0YSy3SmMrcX3kxsvEu4UfiblckRo7CpM0xicKg/1321"
    },
    "liaobe" : null,
    "mobile" : {
        "number" : "18874819762"
    },
    "visitor" : null,
    "accountType" : 1,
    "mobileRewardReceived" : true
}
MongoDB 查询数据的语法格式如下:

db.collection.find(query, projection)
query :可选,使用查询操作符指定查询条件
projection :可选,使用投影操作符指定返回的键。查询时返回文档中所有键值, 只需省略该参数即可(默认省略)

一、查询所有数据

显示所有列

db["user"].find()                # MongoDB写法
db["user"].find().pretty()       # 是find出的数据在命令行中更加美观显示,不至于太紧凑,同select * from user\G;
select * from user;

显示指定列

db["user"].find({},{"liaobe":1,"mobile":1}).pretty()        # 如果projection不为空,不需要查询条件时,必须键入{}    # projection 指定哪些列显示和不显示 (0:不显示 1:显示)

select liaobe,mobile from user\G;

查询json数据二级数据

 "mobile" : {
        "number" : "18874819762"
    },

以上数据,要查询number=18874819762的数据

db["user"].find({"mobile.number":"18874819762"}).pretty()       # 一级.二级.三级,依次类推

二、等于条件查询

db["user"].find({"accountType" : 1}).pretty()
select * from user where accountType=1\G;

三、and

db["user"].find({"uuid" : 12700004,"accountType" : 1,"authType" : 2}).pretty()       # 多个条件用, 隔开
select * from user where uuid=12700004 and accountType=1 and authType=2\G;

四、or

db["user"].find(
    {
        '$or':[
                {"mobile.number":"18874819762"},
                {"weixin.unionId":"o1wS90vp2ENW2Vu-QTnHlcrdU5kA"}
            ]
    },
    {"weixin.nick":1}
).pretty()select nick from user where number='18874819762' or unionId='o1ws90vp2ENW2Vu-QTnH1crdU5kA'

五、< <= > >= (lt lte gt gte)

db["user"].find({'card':{$lt:5}}).pretty()                             # select * from user where card < 5\G;
db["user"].find({'card':{$gt:0,$lt:5}},{"card":1}).pretty()            # select card from user where card > 0 and card <5\G;
db["user"].find({'card':{$lte:5}},{"card":1}).pretty()                # select card from user where card <=5;\G;
db["user"].find({'card':{$gte:0,$lte:5}},{"card":1}).pretty()        # select card from user where card >=0 and card <=5\G;

六、使用in,not in (in,nin)

db["user"].find({"uuid":{$in:[83405282,25594661]}},{"uuid":1,"card":1}).pretty()        # select uuid,card from user where uuid in(83405282,25594661)\G;
db["user"].find({"authType":{$nin:[2,1]}},{"uuid":1,"card":1,"authType":1}).pretty()    # select uuid,card,authType from user where authType not in(2,1)\G;

七、匹配null

db["user"].find({"liaobe":null},{"uuid":1,"weixin.nick":1,"liaobe":1}).pretty()      # select uuid,nick,liaobe from user where liaobei is null\G;

八、like(MongoDB支持正则表达式)

db["user"].find({"weixin.nick":/^随梦/},{"uuid":1,"weixin.nick":1}).pretty()       # select uuid,nick from user where nick like '随梦%'\G;
db["user"].find({"weixin.nick":/袋$/},{"uuid":1,"weixin.nick":1}).pretty()         # select uuid,nick,from user where nick like '%袋'\G;

九、distinct去重

db["user"].distinct("weixin.nick",{"weixin.nick":/^随梦/})       # select distinct(nick) from user where nick like "随梦%";

十、count统计

db["user"].find({"card":{$lt:5}}).count()                      # select count(*) from user where card <5;
db.runCommand(    {       distinct: "user",       key: "weixin.nick",       query: { card: {"$lt":5}}    } ).values.length;           # 先通过find查出数据,然后去重,最后统计

十一、排序

在 MongoDB 中使用 sort() 方法对数据进行排序,sort() 方法可以通过参数指定排序的字段,并使用 1 和 -1 来指定排序的方式,其中 1 为升序排列,而 -1 是用于降序排列。
db["user"].find({"card":{$gt:10,$lt:20}},{"uuid":1,"weixin.nick":1,"card":1}).sort({"card":1})        # select uuid,nick,card from user where card>10 and card<20 asc;
db["user"].find({"card":{$gt:10,$lt:20}},{"uuid":1,"weixin.nick":1,"card":1}).sort({"card":-1})          # select uuid,nick,card from user where card>10 and card<20 desc;

十二、limit

如果你需要在MongoDB中读取指定数量的数据记录,可以使用MongoDB的Limit方法,limit()方法接受一个数字参数,该参数指定从MongoDB中读取的记录条数。
db["user"].find({"card":{$gt:10,$lt:20}},{"uuid":1,"weixin.nick":1,"card":1}).sort({"card":1}).limit(5)

导入导出数据

一、导出数据

   mongodump -h 127.0.0.1:27017 -d test_db -o ./test_db
   如果设有帐号密码请加上-u 和-p参数如下:
   mongodump -u test -p passwd -h 127.0.0.1:27017 -d test_db -o ./test_db
#                         root:帐号   xxxx:密码       game_server 数据库名称         sys_config表名称            sys_config.json要导出的表文件

mongoexport -u root -p xxxx  -d game_server -c sys_config -o sys_config.json
#没有帐号密码的可以不要 -u -p参数

二、导入数据

mongorestore -h 127.0.0.1:27017 -d test_db ./test_db
如果设有帐号密码依然请加上-u 和-p参数如下:
mongorestore -u test -p passwd  -h 127.0.0.1:27017 -d test_db ./test_db
#                         root 帐号     xxx 密码                    game_server 数据库名称                       game_ip_list_config表名称(要恢复的表)                                game_ip_list_config.json文件名(源数据)
mongoimport -u root -p xxx  --db game_server --collection game_ip_list_config --file game_ip_list_config.json
#没有帐号密码的可以不要 -u -p参数

三、可能遇到的错误

需要添加 --authenticationDatabase admin 参数 ,如导入数据命令:
mongorestore --authenticationDatabase admin -u test -p passwd -h 127.0.0.1:27017 -d test_db ./test_db

远程登录用户授权

mongoDB默认用户认证是关闭的。
修改 /etc/mongod.conf 文件。mongoDB默认情况下任何客户端都可以连接27017端口,且没有认证,默认情况下没有管理员帐户。通过修改这个配置文件可以更改为登陆时进行权限认证。
mongoDB中如果想要给某个数据库创建一个用户,需要首先进入该数据库,然后使用addUser命令。在这里也可以将用户设置为只读(db.addUser("jack","jack",true),第三个参数表示是否时“只读用户”)。

要使用超级管理员,需要先连接admin数据库并登陆管理员帐户,然后连接其他数据库就可以行使管理员权限。

用户信息保存及认证过程

类似MySQL将系统用户信息保存在mysql.user表。MongoDB也将系统用户的username、pwd保存在admin.system.users集合中。其中pwd = md5(username + ":mongo:" + real_password)。这本身并没有什么问题。username:mongo:相当于对原密码加了一个salt值,即使攻击者获取了数据库中保存的md5 hash,也没法简单的从彩虹表中查出原始密码。