首先如果没有docker就先下载安装docker

docker search mongodb  # 搜索mongodb镜像
docker pull mongo:latest  # 安装mongodb最新版本, 也可以指定版本
docker images  # 查看本地已经拉取的镜像
docker run -itd --name mongo -p 27017:27017 mongo --auth  # 运行mongo容器, -p指定端口映射, --auth需要密码才能访问容器服务
docker ps  # 查看正在运行的容器信息

# ### 开启用户验证, 开启验证之后游客就只能靠边站了(游客只能玩test测试库), 每次进mongodb都需要验证

exit # 退出容器
docker exec -it mongo /bin/bash # 进入容器
apt-get update # 更新源
apt-get install vim # 安装vim
# 修改 mongo 配置文件 
vim /etc/mongod.conf.orig
配置文件中,加入以下配置,注意authorization前面要加空格,参考其他配置项就能发现
security:
  authorization: enabled

重启mongodb
mongod -f /mongodb/conf/mongo.conf --shutdown 
mongod -f /mongodb/conf/mongo.conf

 

# 给mongodb创建用户

$ docker exec -it mongo mongo admin  # 后面的mongo admin是进入容器并执行的命令, 相当于进入容器,并执行此命令

# 当然上述操作可以分两步操作

$ docker exec -it mongo /bin/bash # 进入mongo容器
/# mongo admin  # 以授权模式进入mongo ,创建了用户之后,都用授权模式进入

# 然后正式创建 userAdminAnyDatabase 用户

# 创建一个名为 root,密码为 123 的用户。
> db.createUser({ user:'myroot',pwd:'123',roles:[{ role:'userAdminAnyDatabase', db: 'admin'},{其他权限字典,可添加多个,也可只要一个}]});
# 尝试使用上面创建的用户信息进行连接。返回1则代表认证成功
> db.auth('root', '123')

 

#  exit  # 退出mongo

#  docker exec -it  mongo /bin/bash   # 进入容器, mongo是容器名 , 或者也可以使用容器id

# mongo admin  # 以授权模式进入mongodb的admin库中 (即需要身份认证才能操作数据库的) , 若用非授权模式启动, 则直接mongo就行了

    如果不加admin, 则默认进入一个test库, 在这个库中也不能进行权限验证

# db.auth('myroot', '123')  # 认证身份, 返回1则代表认证成功

 

用户权限:

一,掌握权限,理解下面4条基本上就差不多

1. mongodb是没有默认管理员账号,所以要先添加管理员账号,在开启权限认证。
2. 切换到admin数据库,添加的账号才是管理员账号。
3. 用户只能在用户所在数据库登录(也就是进行身份验证db.auth(...)),包括管理员账号。
4. mongo的用户是以数据库为单位来建立的,每个数据库有自己的管理员。
5. 管理员可以管理所有数据库,但是不能直接管理其他数据库,要先在admin数据库认证后才可以(添加root超级权限)。
注:帐号是跟着库走的,所以在指定库里授权,必须也在指定库里验证

 

二  用户权限说明

Read:允许用户读取指定数据库
readWrite:允许用户读写指定数据库
dbAdmin:允许用户在指定数据库中执行管理函数,如索引创建、删除,查看统计或访问system.profile
userAdmin:允许用户向system.users集合写入,可以找指定数据库里创建、删除和管理用户
clusterAdmin:只在admin数据库中可用,赋予用户所有分片和复制集相关函数的管理权限。
readAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读权限
readWriteAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的读写权限
userAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的userAdmin权限
dbAdminAnyDatabase:只在admin数据库中可用,赋予用户所有数据库的dbAdmin权限。不能在其他数据库中建数据集合
root:只在admin数据库中可用。超级账号,超级权限,可以删除其他用户(删除用户的时候只能在admin数据库下删),而且root用户还能在其他数据库中建数据集合

 

# 简单点吧, 你如果是dbAdminAnyDatabase用户, 你就可以创建普通用户, 并且给普通用户对于某个或某些数据库的读/写权限

首先需要 use admin
验证身份 db.auth('myroot', '123')  # 就相当于用myroot这个用户登录mongodb
use db1  # 创建db1数据库, 并且选择这个数据库
db.createCollection('article')  # 创建article数据集合
会发现报错 not authorized on db1 to execute command  # 没有权限执行创建数据集合的命令
回到admin权限库 use admin
db.grantRolesToUser("myroot", [{role: "root", db: "admin"}])  # 给myroot这个用户添加对于admin权限管理库的超级管理员(root)权限
添加了之后就可以横行无阻了, 就可以去其他数据库中肆意妄为了

# 撤销角色权限, 比如说 dbAdminAnyDatabase 用户去掉自己的root身份 db.revokeRolesFromUser("myroot", [{role: "root", db: "admin"}])  
    # 撤销自己的root身份

# 授予角色权限, 上面已经提到了 db.grantRolesToUser("myroot", [{role: "root", db: "admin"}]) 

# 创建普通用户 db.createUser({ user:'chen',pwd:'111',roles:[{ role:'readWrite', db: 'db1'}]});  
    # 用户chen对于db1数据库有读写权限, 对于其他数据库没有任何权限
    # ### 注意 : 创建普通用户得去到对应的库下面创建, 这样创建的用户才能管理这个库

> db.system.users.find().pretty() 或者使用 > db.system.users.find()  # 在admin库下查看全局所有用户
show users  # 查看当前库下的用户

# 删除用户 :
> db.system.users.remove({_id:"XXX.XXX"})  # 根据id删除用户
> db.system.users.remove({user:"XXXXXX"})  # 根据用户名删除用户

# 更改密码 : db.changeUserPassword("myroot", "666")  # 将myroot用户的密码改为666, 当然事先你得用myroot用户登录

# 登录mongodb : 一般用mongo admin直接进入admin库下,然后进行身份验证就行了, 或者 mongo -u myroot -p 123 "admin"
    远程登录 mongo -host 192.168.3.17 --port 27017 -u myroot -p 123 "admin"

 

# ### MongoDB常用命令

> show dbs #显示数据库列表 
> show collections #显示当前数据库中的集合(类似关系数据库中的表)
> show users #显示用户
> use <db name> #切换当前数据库,如果数据库不存在则创建数据库。 
> db.help() #显示数据库操作命令,里面有很多的命令 
> db.foo.help() #显示集合操作命令,同样有很多的命令,foo指的是当前数据库下,一个叫foo的集合,并非真正意义上的命令 
> db.foo.find() #对于当前数据库中的foo集合进行数据查找(由于没有条件,会列出所有数据) 
> db.foo.find( { a : 1 } ) #对于当前数据库中的foo集合进行查找,条件是数据中有一个属性叫a,且a的值为1

MongoDB没有创建数据库的命令,但有类似的命令。 如:如果你想创建一个“myTest”的数据库,先运行use 
myTest命令,之后就做一些操作(如:db.createCollection(‘user’)),这样就可以创建一个名叫“myTest”的数据库。

其他命令
> db.dropDatabase() #删除当前使用数据库
> db.cloneDatabase("127.0.0.1") #将指定机器上的数据库的数据克隆到当前数据库
> db.copyDatabase("mydb", "temp", "127.0.0.1") #将本机的mydb的数据复制到temp数据库中
> db.repairDatabase() #修复当前数据库
> db.getName() #查看当前使用的数据库,也可以直接用db
> db.stats() #显示当前db状态
> db.version() #当前db版本
> db.getMongo() #查看当前db的链接机器地址
> db.serverStatus() #查看数据库服务器的状态

查看分片结果:
db.printShardingStatus()

测试:向test数据库的user表中添加10w条数据:
use test
for(var i=0;i<100000;i++){
  db.user.insert({"name":"test"+i,"age":i});
}

 

# ### 登录命令

# ### 登录
mongo -uroot -p123  admin # 方法一
mongo admin 快捷进入mongo的admin权限库 然后 db.auth('root', '123')  # 方法二
mongo  # 进去之后 use admin 然后 db.auth('root', '123')  # 方法三

 

# ### mongodb的三个结构: 数据库db/数据集(集合)collection/文档xxx, 分别对应着mysql中的数据库/数据表/数据记录

# ### 数据库相关操作

show dbs  # 显示所有数据库
use db1  # 使用db1数据库,如果数据库中没数据,则该数据库也就不存在
db.stats()  # 显示当前数据库的各种信息
db.dropDatabase()  # 删除当前数据库, 包括数据库中的数据集
db  # 显示当前所在的数据库

 

 # ### 数据集相关操作

show collections  # 显示当前库中所有数据集
db.createCollection("user")  # 创建user数据集
db.users.renameCollection("staff")  # 将user数据集改名为staff
db.staff.drop()  # 删除staff数据集

 

# ### 文档(数据)相关操作

db.article.insert( {'title': '博客1','content': '开始写博客'} );  # 往article数据集中插入一条数据, 就相当于给insert函数传参一个字典, 
        # 其中键可以不加引号,会自动识别, 单双引号都可以用
db.article.find()  # 显示article数据集中所有文档
for(var i = 3; i <=10; i++ ) {  # for循环插入多个文档, 每条数据的字段不相同也能插入,这就是mongodb的柔软性
    db.article.insert({
        title: "我的第" + i + "篇博客"
    });
}
db.article.count()  # 查看article数据集有多少条数据
db.article.remove({})  # 删除article数据集中所有文档

 

# ### find语法

db.数据集名.find({"字段名":"条件"})
$gte, $gt, $lte, $lt  # 大于等于, 大于, 小于等于, 小于
$eq, $ne  # 等于, 不等于
正则表达式:/k/, /^k/  # 值中包含k, 值以k开头  
        # ### 注意, 正则表达式两边不要用引号包起来,会识别不了
db.[collection_name].distinct("field_name");  # 取出这个字段并排序, 结果就是里面有多个字段的数组
use komablog;
db.posts.remove({});

测试 :
use komablog;
db.posts.remove({});
db.posts.insert({title:"怪物猎人世界评测","rank":2,"tag":"game"});
db.posts.insert({title:"纸片马里奥试玩体验","rank":1,"tag":"game"});
db.posts.insert({title:"Utunbu16LTS的安装","rank":3,"tag":"it"});
db.posts.find({"tag": "game"});  # 取出tag是game的文档
db.posts.find({"rank": {$gte: 2}});  # 取出rank 大于等于2的文档
db.posts.find({"title": /马/});  # 取出title中包含'马'的
db.posts.find({"title": /^U/});  # 取出以'U'开头的
db.posts.distinct("tag");  # 取出tag字段的所有值,(自动去重并排序) 结果 : ["game", "tag"]

 

db.[collection_name].find({筛选条件}, {field1: true, field2: 1})  # 第二个字典里可以填写想/不要哪些字段

db.posts.find();
db.posts.find({"title": /u/, "rank":{$gte:5} });  # 相当于与, 找到两个条件同时成立的文档
db.posts.find({$or: [{"title": /u/}, {"rank":{$gte:4}}] });  # 或
db.posts.find({"rank": {$in: [3,4]} });  # rank字段值在[3, 4]中选
db.posts.insert({ "title":"惊!骑士发生重大交易", "istop": false });  # 添加一条新文档, 有一个新的字段istop
db.posts.find({"istop": {$exists: true} });  # 找到包含istop这个字段的文档, 结果就是刚刚我们插入的那条数据

db.posts.find({"tag": "game"},{title:true,rank:1});  # 取出tag是game的title字段和rank字段, 其中true和1是等价的,都代表true
        而false和0也是等价的,都代表不取这个字段, 其实每次取默认都取_id字段, 所以可以用_id : 0来不取_id

 

sort()  # 排序
limit()  # 取出多少
skip()  # 跳过多少再取

db.posts.find();
db.posts.find({}, {_id:0}).sort({rank:1});  # 按照rank字段进行升序排序
db.posts.find({}, {_id:0}).sort({rank:-1});  # 按照rank字段进行降序排序
db.posts.find({}, {_id:0}).limit(3);
db.posts.find({}, {_id:0}).sort({rank:-1}).limit(3);
db.posts.findOne({}, {_id:0});  # findOne只取一个,相当于后面加.limit(1)
db.posts.find({}, {_id:0}).limit(3);  # 取前三个
db.posts.find({}, {_id:0}).skip(3).limit(3);  # 跳过前三个再取三个

 

update(<filter>, <update>, <options>)  # 第一个参数为筛选条件, 第二个为更新选项, 第三个为其他选项
$set   # 修改或新增, 有这个字段就更新, 没有这个字段就添加 , 不加$set就是直接移除原有字段, 变成新字段了
update命令参考官网 https://docs.mongodb.com/manual/reference/method/db.collection.update

use komablog;
db.posts.findOne({"title":"怪物猎人世界评测"});
db.posts.update({"title":"怪物猎人世界评测"}, {$set: {"rank": 10} });
db.posts.find();
db.posts.update({"title":"怪物猎人世界评测"}, {"rank": 99});  # 将title是怪物猎人的文档更新为只剩'rank' : 99这一个字段
db.posts.find();
db.posts.update({"tag":"it"}, {$set: {"rank": 50}});  # 将tag为it的文档的rank更新为50,默认只更新一条
db.posts.find();
db.posts.update({"tag":"it"}, {$set: {"rank": 60}}, {multi: true});  # multi: true指定更新所有符合调价你的文档
db.posts.find();

 

$inc  # 递加, increase
$mul  # 相乘 multiply
$rename  # 改名
$set  # 新增or修改
$unset  # 字段删除

$ mongo
use komablog;
db.posts.find({title:"纸片马里奥试玩体验"}, {_id:0});
db.posts.update({title:"纸片马里奥试玩体验"}, {$inc: {rank: 1}});  # 原来rank的基础上加1
db.posts.update({title:"纸片马里奥试玩体验"}, {$mul: {rank: 2}});  # 原来rank的基础上乘2
db.posts.update({title:"纸片马里奥试玩体验"}, {$rename: {"rank": "score"}});  # 将rank字段改名为score
db.posts.update({title:"纸片马里奥试玩体验"}, {$set: {"istop": true}});  # 新增字段istop: true
db.posts.update({title:"纸片马里奥试玩体验"}, {$unset: {"istop": true}});  # 删掉字段istop: true
db.posts.find({title:"纸片马里奥试玩体验"}, {_id:0});

 

upsert : true  # 相对于文档(记录)有则更新,无则新增 ; 注意,之前那个$set是相对于字段的修改或新增, 需要区分一下
        # 默认为false
.remove()  # 条件删除数据(文档)

$ mongo
use komablog;
db.posts.find({}, {_id:0});
db.posts.update({title:"其实创造比大志好玩"}, {title:"其实创造比大志好玩", "rank":5,"tag":"game"});  # 没找到title为这个的数据,无法直接更新
db.posts.find({}, {_id:0});
db.posts.update({title:"其实创造比大志好玩"}, {title:"其实创造比大志好玩", "rank":5,"tag":"game"}, {upsert:true});  
        # 有则更新,无则新增,所以这里能够更新
db.posts.remove({title:"其实创造比大志好玩"});
db.posts.find({}, {_id:0});

 

# ### 数据集的索引

db.posts.getIndexes()  # 查看当前数据集的索引
createIndex({...}, {...})  # 创建索引, 跟条件(创建什么样的索引?主键/普通索引等等), 创建索引为了方便查找
dropIndex({...})  # 删除索引

$ mongo
use komablog;
db.posts.getIndexes();
db.posts.createIndex({rank:-1});  # 以rank字段降序创建一个索引
db.posts.dropIndex({rank:-1});  # 删除刚刚创建的索引
db.posts.createIndex({title:1}, {unique:true});  # 创建一个以title字段升序的 唯一 索引
db.posts.find({}, {_id:0});
db.posts.insert({title:"怪物猎人世界评测"});  
        # title是唯一索引,并且值已经有怪物猎人了,再插入同样的会报错,duplicate key error collection(重复键错误数据集)
        # 当然你如果插入一条没有title字段的文档, 也会报错, 错误原因是主键title不能为null

> db.posts.getIndexes();
[
    {
        "v" : 2,
        "key" : {
            "_id" : 1  # 只有_id这一个索引字段
        },
        "name" : "_id_",  # 这是mongodb的默认索引
        "ns" : "komablog.posts"
    }
]

 

# ### 备份与恢复

mongodump  # 备份
mongorestore  # 恢复
# 参考博客 

mongodump -uroot -p123 --authenticationDatabase admin -d komablog  # 备份, 在mongodb外边执行的
        # 其中--authenticationDatabase admin指的是在admin权限库中验证-u和-p带的用户名和密码, 作为游客的话就不认证
        # -d 指定备份的数据库; -h 指明数据库宿主机的IP ; -c 指明collection数据集的名字; -f 指明要导出那些列(字段)
        # -o 指明到要导出的文件名,默认为dump ; -q 指明导出数据的过滤条件 ; --type 指定文件类型
mongorestore -uroot -p123 --authenticationDatabase admin --drop  # 恢复, 在mongodb外边执行的
        # 上面有的参数就不说了, 还有一个新参数 --drop 插入之前先删除原有的(就相当于重写)
        # --headerline 指明第一行是列名,不需要导入。
        # -j 同时运行的插入操作数(默认为1),并行
# 备份完了删数据集, 然后出来ls看一下备份文件, 然后恢复, 进去mongodb看数据又回来了

 

# ### 与python的交互

pip install pymongo
from pymongo import *
client = MongoClient('mongodb://127.0.0.1:27017')  # 无安全认证的mongo连接
client = MongoClient('mongodb://用户名:密码@127.0.0.1:27017/验证数据库')  # 有安全认证的mongo连接
# pymongo有两个类比较重要
# 1 database类,用来获取数据库
db = client.db1  # 指定连接db1数据库

# 2 collection类
主要方法:
insert_one  insert_many  update_one  update_many  delete_one  delete_many  find_one  find

article_obj = db1.article  # 获取article集合对象,接下来就可以操作一波了
s1_id = article_obj.insert_one({'name': '张三丰', 'age': 61}).inserted_id  # 后面加个.insert_id, 可以返回插入数据的id, 当然也可以不加.insert_id不看
print(s1_id)
article_obj.update_one({'name': '张三丰', 'age': 61}, {$set: {name: '张四丰'}})

# .sort() 排序, 升序用ASCENDINT, 降序用DESCENDING
# 错了 好像现在不能用ASCENDINT和DESCENDING,得用1和-1
res = article.find().sort([ ('rank',1),('tag',-1) ])  # 注意, 这里不是一个字典了,中间是逗号

# ### 实例
from pymongo import MongoClient

client = MongoClient('mongodb://root:123@106.53.21.61:27017/admin')
# 1 database类,获取数据库
db1 = client.komablog
posts_obj = db1.posts
# s1_id = posts_obj.insert_one({'name': '张三丰', 'age': 61}).inserted_id  # 后面加个.insert_id, 可以返回插入数据的id,
# 当然也可以不加.insert_id不看
# print(s1_id)
# posts_obj.update_one({'name': '张三丰'}, {'$set': {'name': '张四丰'}})
# 其他操作都是按照方法来了,posts_obj就相当于在mongo中的db.posts
# res = posts_obj.find({'rank': {"$gte": 1}}).sort([('rank', 1), ('tag', -1)])
res = posts_obj.find().sort([('rank', 1), ('tag', -1)])
for i in res:
    print(i)