官网下载mongondb
https://www.mongodb.com
根据系统选择相应版本。(这里是3.6,最新的版本配置不一样,看官网)
概念
- database
数据库 - collection
集合,多个集合组成数据库。 - document
文档,多个文档组成集合。
文档中的数据是 键值对, 类JSON的二进制格式,简称 BSON(Binary JSON)
Winddows下安装:
安装
配置数据库文件夹
比如
D:\program\MongoDB\Server\3.6
在该目录下新建文件夹data(自定)
在data下再建一个文件夹db(自定)
启动服务端 并指定数据库路径
返回到\3.6目录下,shift+右键打开CMD窗口
输入 mongod --dbpath D:\program\MongoDB\Server\3.6\data\db 回车。
验证服务端是否启动成功,浏览器输入:localhost:27017
在\3.6目录下,再打开一个CMD,输入mongo,启动客户端。
在这里,可以进行交互操作。
将mongondb配置成系统服务
在新建的data文件夹下,再创建日志文件夹logs
进入该文件夹,创建mongo.log文件,右键,属性,安全,复制路径。
在\3.6\bin下,以管理员身份启动CMD,输入命令:
mongod --bind_ip 0.0.0.0 --logpath D:\program\MongoDB\Server\3.6\data\logs\mongo.log --logappend --dbpath D:\program\MongoDB\Server\3.6\data\db --port 27017 --serviceName "MongoDB" --serviceDisplayName "MongoDB" --install
回车,配置完成。在 任务管理器,服务 中查看是否配置成功。
Robomongo 是mongondb的一个可视化客户端。搜索下载。
Linux下安装:
apt-get install mongodb
启动服务端:mongod
启动客户端:mongo
上面的方式安装的版本比较旧,推荐去官网下载后缀是tgz的源码包,然后用 tar -zxvf 包名.tgz 解压。配置文件同样用YAML格式的。自行新建个目录存放数据和日志,比如 /root/mongo/data 和
/root/mongo/mongod.log
启动服务:mongod -f xx.conf
启动客户端:mongo host:port
日志文件提示:
WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
解决方法:
echo "never" > /sys/kernel/mm/transparent_hugepage/enabled
命令行
- mongod
启动服务端 (按上面方法配置成系统服务,并已经启动,可忽略) - mongo
启动客户端
常用命令
- show dbs
查看所有数据库 - db
查看当前连接在哪个数据库 - use 数据库名
切换数据库
若不存在,则创建,需写入数据,不然退出就消失。 - show collections
显示当前数据库集合数量 - db.getName()
获取所在数据库名称 -
db.stats()
获取所在数据库状态
数据库CRUD(增删改查)
增
- db.集合名.insert()
插入一条文档,括号内填要插入的内容。
删
- db.集合名.remove()
删除 该集合下 满足条件的所有文档,括号内填条件。 - db.集合名.drop()
删除当前集合 - db.dropDatabase()
删除当前数据库
改
- db.集合名.update({k1:v1}, {$set: {k1:v2}})
将 {k1: v1} 更新为 {k1: v2}
只更新一个文档.
若 set 后面是 {k2: v2},表示在 {k1: v1} 文档内,增加一条 k2:v2 记录。
只更新一个文档.
查
- db.集合名.find()
查看该集合下 所有 文档内容。 - db.集合名.find({查询条件})
查询满足条件的 所有 文档。 - db.集合名.find().sort({field:1 or -1}) / .skip(num) / .limit(num)
将找到的结果
sort : 按 field 字段排序,1代表正序,-1代表倒序
skip: 跳过num个结果。
limit:只取num个结果。 - db.集合名.find({},{field1:1,field2:1,_id:0})
从结果中,抽出指定字段,1代表取该字段。
默认会取出 _id 这个字段,若不取该字段,要显式指明为 0
pymongo
python里操作mongodb的工具。
安装
- pip3 install pymongo
- pipenv install pymongo
两种方式,自行选择。
使用
- 插入数据
collection.insert(数据1[,数据2])
在MongoDB中,每条数据其实都有一个_id属性来唯一标识。如果没有显式指明该属性,MongoDB会自动产生一个ObjectId类型的_id属性。insert()方法会在执行后返回_id值.
在PyMongo 3.x版本中,推荐使用
insert_one() 和 insert_many()
分别返回如下对象。
调用返回对象的 inserted_id 或 inserted_ids 能获取到 插入数据的 _id 属性。
- 查询单条数据
find_one()
存在,返回结果,字典形式。
若不存在,返回None
查询所有满足条件的数据
find()
返回的是 Cursor对象,相当于生成器,可以遍历得到结果。比较符号表
e.g.
collection.find({'age': {'$gt': 20}})
这里的查询条件值,不是单纯数字,而是字典
其键名是比较符号$gt
, 值是 20
-
功能符号表
详细可参考官方文档
https://docs.mongodb.com/manual/reference/operator/query/
- 统计数量
返回结果调用 count() 方法 - 排序
直接调用 sort() 方法,并在其中传入排序的字段及升降序标志即可。示例如下:
collection.find().sort('name', pymongo.ASCENDING)
或者是 DESCENDING (降序) - 偏移
调用 skip() 方法,括号传入要忽略的个数。
比如偏移2,就忽略前两个元素,得到第三个及以后的元素
在数据库数量非常庞大的时候,如千万、亿级别,最好不要使用大的偏移量来查询数据,因为这样很可能导致内存溢出。
此时可以使用类似如下操作来查询:
from bson.objectid import ObjectId
collection.find({'_id': {'$gt': ObjectId('593278c815c2602678bb2b8d')}})
这时需要记录好上次查询的_id。 - 指定要获取的结果 个数
调用 limit() 方法,括号传入数字。 - 更新
update() 方法
返回结果是 字典
ok代表执行成功,nModified代表影响的数据条数.
推荐使用 update_one() 和 update_many()
返回的是 UpdateResult类型
分别调用 matched_count 和 modified_count 属性,可以获得 匹配的数据条数 和 影响的数据条数。 - PyMongo还提供了一些组合方法,如find_one_and_delete()、find_one_and_replace()和find_one_and_update(),它们是查找后删除、替换和更新操作,其用法与上述方法基本一致。
注意
update({条件}, {替换的内容})
这是找到满足条件的文档,并用 后面的内容替换。
update({条件}, {'$set': {修改/增加的内容}})
这样才是 修改或者增加内容。
设置 连接帐号和密码
show dbs
use admin
进入admin数据库创建管理员账户
db.createUser({user: "useradmin", pwd: "adminpassword", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
mongodb中的用户是基于身份role的,该管理员账户的 role是 userAdminAnyDatabase。 ‘userAdmin’代表用户管理身份,’AnyDatabase’ 代表可以管理任何数据库。验证第3步用户添加是否成功
db.auth("useradmin", "adminpassword")
如果返回1,则表示成功。
exit退出系统-
修改配置
找到 bin 目录下的 mongod.cfg配置文件
找到#security: 取消注释,修改为:
security:
authorization: enabled
比如下面这样配置,注意保存格式选 utf-8。
(注:采用的是 YAML语法 不能使用tab键占位,会报错!需要占位请使用空格键)
重启 mongodb 服务
- 关闭服务
- 命令行更新服务配置
开启验证 --auth
mongod --auth --config D:\program\MongoDB\Server\4.0\bin\mongod.cfg --install- 开启服务
- 命令行输入mongo(需将该命令配置到环境变量里)
进入mongodb,用第3步的 管理员账户登录,用该账户创建其他数据库管理员账号
use admin
db.auth("useradmin", "adminpassword") - 新建你需要管理的mongodb 数据的账号密码。
use yourdatabase
db.createUser({ user: "youruser", pwd: "yourpassword", roles: [{ role: "dbOwner", db: "yourdatabase" }] })
dbOwner 代表数据库所有者角色,拥有最高该数据库最高权限
注意
数据库帐号是跟着数据库的,哪里创建哪里认证.
- 连接你的数据库
mongodb://name:password@localhost:port/yourdatabase
用户管理
https://docs.mongodb.com/manual/reference/method/db.getUser/
- db.system.users.find().pretty()
格式化显示 创建的用户
这条命令在 admin 数据库下,且用户角色为userAdminAnyDatabase 才有效。 - db.getUsers()
- db.changeUserPassword("username", "password")
- db.dropUser("username")
- db.dropAllUsers()
- db.revokeRolesFromUser("username",[{role:"权限",db: "数据库"}])
删除权限 - db.grantRolesToUser("username",[{role:"权限",db: "数据库"}])
增加权限
用户角色
分两类,一类是用户管理员,只能管理用户,不能操作数据库。
另一类是数据库管理员,拥有操作数据库权限。
索引
简单的说,索引就是将文档按照某个(或某些)字段顺序组织起来,以便能根据该字段高效的查询。
- 创建:
单字段索引:
db.集合名.createIndex( { 字段: 排序} )
多字段索引:
db.集合名.createIndex( { 字段1: 排序, 字段2:排序} )
排序用 1表示升序,-1表示降序。
- 查看索引:
db.集合名.getIndexes()
返回内容如下:
- 删除索引:
db.集合名.dropIndex("索引名称")
聚合 aggregate
语法:
db.集合名.aggregate( [ { 管道1:{ 表达式1 } }, { 管道2:{ 表达式2 } } ] )
中括号内可以接多个管道,直接用逗号分隔。
常用管道:
- $group:将集合中的文档分组,可用于统计结果。
- $match:用于过滤数据,只输出符合条件的文档。
- $project:修改输入文档的结构。可以用来重命名、增加或删除字段, 也可以用于创建计算结果以及嵌套文档。
- $sort:将输入文档排序后输出。
- $limit:用来限制MongoDB聚合管道返回的文档数。
- $skip:在聚合管道中跳过指定数量的文档,并返回余下的文档。
- $unwind:将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值。
表达式
- 处理输入文档并输出.
- 语法:
表达式:"$字段名" -----加个美元符号,表示获取该字段的值。
常用表达式:
- $sum:计算总和,$sum: 1 表示计数。
- $avg: 计算平均数。
- $min: 取最小值。
- $max: 取最大值。
- $first: 取第一个文档数据。
- $last: 取最后一个文档数据。
- $push: 将字段的值 push到 数组中。
示例
- $group:
- db.集合名.aggregate([
{$group:{_id: '$name',count:{$sum:1}}}
])
# 其中 _id 是固定的, 表示字段;count也是字段,可以自定义。
# 表示按姓名进行分组,并统计该名字的个数。
返回结果
- $match:
- db.集合名.aggregate([
{$match:{age: {$gt: 22}}}
])
# 将 age 字段,大于 22的数据筛选出来。
- $match
- $sort
- $project
- db.集合名.aggregate([
{$match:{age: {$gt: 22}}},
{$sort:{age:1}},
{$project:{_id:0, name:1,age:1, address:1}}
])
# 筛选出 age 大于 22的数据,并按 age 升序排列,
# 最后只显示 name,age,address字段。
- $unwind
- db.集合名.insert({_id:1,name:"xyz",hobby:["eat","sleep","play"]})
- db.集合名.aggregate([{$unwind:"$hobby"}])
返回结果
备份和恢复
备份
命令行:
mongodump -u 用户名 -p 密码 -h dbhost:port -d dbname -o 备份目录名
恢复
命令行:
mongorestore -u 用户名 -p 密码 -h dbhost:port -d dbname --dir 备份目录名\数据库名
replica set
部署集群
采用3个节点的方式,一主Master,一从Slaver,一仲裁Arbiter。
本文演示的是一台机器上,通过端口来区分不同的服务端。
新建3个配置文件分别是master.conf,slaver.conf,arbiter.conf
配置文件有两种写法,一是直接用 变量=值 的形式,另一种是用YAML语法形式。
示例配置一,"变量=值"的形式
# master.conf
dbpath=D:\program\MongoDB\Server\4.0\ts\master
logpath=D:\program\MongoDB\Server\4.0\ts\master.log
pidfilepath=D:\program\MongoDB\Server\4.0\ts\master.pid
directoryperdb=true # 为每一个数据库按照数据库名建立文件夹存放
logappend=true
replSet=testrs # replica set的名字
bind_ip=127.0.0.1 # 实际部署修改成相应的ip。
port=27018
oplogSize=10000 # mongodb操作日志文件的最大大小。单位为Mb,默认为硬盘剩余空间的5%
# fork=true # 后台运行,在linux下有效。
noprealloc=true # 不预先分配存储.
示例配置二,YAML格式
# master.conf
systemLog:
destination: file
path: D:\program\MongoDB\Server\4.0\ts1\M\mongod.log
logAppend: true
storage:
dbPath: D:\program\MongoDB\Server\4.0\ts1\M\data
directoryPerDB: true
security:
# authorization,这条只需要在主节点配置即可,从节点有,也是可以的。
authorization: enabled
keyFile: D:\program\MongoDB\Server\4.0\ts1\M\key.txt
net:
bindIp: localhost
port: 27018
replication:
# 这里是设置 replica set的名字,三个配置文件中要一致。
replSetName: testrs
oplogSizeMB: 1000
#processManagement:
#fork: true
# 这里的 fork,是在Linux下后台运行,在windows下无效。
# windows可以考虑将起配置成系统服务。
开启3个mongodb服务:
mongod -f path\to\master.conf
mongod -f path\to\slaver.conf
mongod -f path\to\arbiter.conf
连接上面的master:
- mongo localhost:27018
- use admin
- cfg={ _id:"testrs", members:[ {_id:0,host:'127.0.0.1:27018',priority:2},
{_id:1,host:'127.0.0.1:27019',priority:1},
{_id:2,host:'127.0.0.1:27020',arbiterOnly:true}] }
- rs.initiate(cfg)
# 上面的_id后的"testrs"是replica set的名字,你可以自定义。
# priority:优先级,数字越大越优先。
等待生效...配置的生效时间根据不同的机器配置会有长有短.
- rs.status() # 查看信息,看"members".确认是否生效。
完成。
测试1:
在master上写数据。
在slaver上查数据,会提示报错"errmsg" : "not master and slaveOk=false",输入:rs.slaveOk(),再次
查询就能查到数据。
测试2:
关掉master服务器,模拟故障,此时slaver服务自动变成primary。当master恢复后,master是primary,
slaver是secondary。因为设置了优先级。
添加成员:
rs.add({"ip:port"})
删除成员:
rs.remove({"ip:port"})
安全
集群之间用 keyfile 验证,官方推荐生产环境用x.509证书身份验证,客户端访问数据库使用 用户权限 来验证。
keyfile内容是6-1024个字符且只能包含base64字符集。linux下要给keyfile文件400权限,windows不需要。
# linux下,用这个命令生成keyfile,路径自定。
openssl rand -base64 741 > /home/mongodb/keyfile
chmod 400 keyfile
每个集群成员都要保存一份keyfile,并在配置文件里指明路径。
配置安全验证后,
rs.status()查看集群状态,该命令要root权限的用户才能执行,dbOwner也不能执行。
root权限只能在admin这个数据库存在。
注意:db.dropAllUsers(),不要在userAdminAnyDatabase的权限用户下,执行。
设置安全验证后,pymongo和mongoengine连接方式
from mongoengine import connect
from pymongo import MongoClient
connect(host='mongodb://username:password@host:port,host1:port1/databasename?replicaSet=yourname')
MongoClient("mongodb://username:password@host:port,host1:port1/databasename?replicaSet=yourname")
transaction
在MongoDB中,对单个文档的操作是原子操作。
多文档事务,只支持副本集(replica set)。
Transactions for sharded clusters are scheduled for MongoDB 4.2
- pymongo中实现多文档事务
db = pymongo.MongoClient("mongodb://username:password@host:port,host1:port1/databasename?replicaSet=yourname")
with db.start_session()as s:
s.start_transaction()
db.test.gan.insert_one({'name': "我是py"}, session=s)
db.test.gan.insert_one({'name': "我是py2"}, session=s)
s.commit_transaction()