MongoDB

官网下载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


命令行

  1. mongod
    启动服务端 (按上面方法配置成系统服务,并已经启动,可忽略)
  2. mongo
    启动客户端
常用命令
  • show dbs
    查看所有数据库
  • db
    查看当前连接在哪个数据库
  • use 数据库名
    切换数据库
    若不存在,则创建,需写入数据,不然退出就消失。
  • show collections
    显示当前数据库集合数量
  • db.getName()
    获取所在数据库名称
  • db.stats()
    获取所在数据库状态


    image.png

数据库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()
    分别返回如下对象。
    image.png

image.png

调用返回对象的 inserted_idinserted_ids 能获取到 插入数据的 _id 属性。

  • 查询单条数据
    find_one()
    存在,返回结果,字典形式。
    若不存在,返回None
  • 查询所有满足条件的数据
    find()
    返回的是 Cursor对象,相当于生成器,可以遍历得到结果。

  • 比较符号表

e.g.

collection.find({'age': {'$gt': 20}})
这里的查询条件值,不是单纯数字,而是字典
其键名是比较符号 $gt, 值是 20

  • 功能符号表


    image.png

详细可参考官方文档
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() 方法
    返回结果是 字典
    image.png

    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': {修改/增加的内容}})
这样才是 修改或者增加内容。

设置 连接帐号和密码

  1. show dbs

  2. use admin
    进入admin数据库

  3. 创建管理员账户
    db.createUser({user: "useradmin", pwd: "adminpassword", roles: [{ role: "userAdminAnyDatabase", db: "admin" }] })
    mongodb中的用户是基于身份role的,该管理员账户的 role是 userAdminAnyDatabase。 ‘userAdmin’代表用户管理身份,’AnyDatabase’ 代表可以管理任何数据库。

  4. 验证第3步用户添加是否成功
    db.auth("useradmin", "adminpassword")
    如果返回1,则表示成功。
    exit退出系统

  5. 修改配置
    找到 bin 目录下的 mongod.cfg配置文件
    找到#security: 取消注释,修改为:
    security:
    authorization: enabled
    比如下面这样配置,注意保存格式选 utf-8。
    (注:采用的是 YAML语法 不能使用tab键占位,会报错!需要占位请使用空格键)


    image.png
  6. 重启 mongodb 服务

  • 关闭服务
  • 命令行更新服务配置
    开启验证 --auth
    mongod --auth --config D:\program\MongoDB\Server\4.0\bin\mongod.cfg --install
  • 开启服务
  1. 命令行输入mongo(需将该命令配置到环境变量里)
    进入mongodb,用第3步的 管理员账户登录,用该账户创建其他数据库管理员账号
    use admin
    db.auth("useradmin", "adminpassword")
  2. 新建你需要管理的mongodb 数据的账号密码。
    use yourdatabase
    db.createUser({ user: "youruser", pwd: "yourpassword", roles: [{ role: "dbOwner", db: "yourdatabase" }] })
    dbOwner 代表数据库所有者角色,拥有最高该数据库最高权限
注意

数据库帐号是跟着数据库的,哪里创建哪里认证.

  1. 连接你的数据库
    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()
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 157,198评论 4 359
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,663评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 106,985评论 0 237
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,673评论 0 202
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 51,994评论 3 285
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,399评论 1 211
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,717评论 2 310
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,407评论 0 194
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,112评论 1 239
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,371评论 2 241
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,891评论 1 256
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,255评论 2 250
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,881评论 3 233
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,010评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,764评论 0 192
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,412评论 2 269
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,299评论 2 260

推荐阅读更多精彩内容