一篇搞定MongoDB

时间:2021-06-27 08:40:50

  MongoDB最基础的东西,我这边就不多说了,这提供罗兄三篇给大家热身

  1. MongoDB初始
  2. MongoDB逻辑与物理存储结构
  3. MongoDB的基础操作

  最后对上述内容和关系型数据做个对比

  • 非关系型数据库的优势
  1. 性能  --NoSQL是基于键值对的,不需要经过SQL层的解析,所以性能非常高
  2. 可扩展性  --因为基本键值对的,数据之间没有耦合性,所以非常容易水平扩展
  • 关系型数据库的优势
  1. 复杂查询  --可以进行多表复杂查询
  2. 事务支持  --要求安全性高的数据访问得以实现

1.高级查询命令

  条件查询

  1.1 大于 小于

  • $gt 大于  实例:db.singer.find({"age":{$gt : 50}})
  • $lt  小于  实例:db.singer.find({"age":{$lt : 30}})
  • $gte 大于等于   实例:db.singer.find({"age":{$gte : 50}})
  • $lte  小于等于   实例:db.singer.find({"age":{$lte : 30}})

  1.2 选择区间

  • db.集合名.find({"键名":{$gt:值1,$lt:值2}})   实例:db.singer.find({"age":{$gte:30, $lt:40}})

  1.3 不等于

  • $ne 不等于  实例:db,singer.find({"country":{$ne:''china"}})

  1.4 in和not in

  • $in 在集合中  实例:db.singer.find({"num":{$in:["值1","值2"]}})
  • $nin  不在集合中  实例:db.singer.find({"num":{$nin:["值1","值2"]}})

  1.5 数组个数

  • $size 值的个数  实例:db.singer.find({"works":{$size:3}})

  1.6 是否存在

  • $exists 是否存在某个键名(true|false)  实例:db.singer.find({'height':{$exists:true}})

  1.7 或

  • $or 或者,多个条件满足一个就行了  实例:db.singer.find({$or:[{'name':'laoliu'},{'sex':'女'}]})

  1.8 模糊查询

  • db.集合.find('键':值)  值必须是正则表达式(js正则)  实例:db.singer.find({"name":/刘/})

  排序

  • db.集合名.find().sort({"键名1":1, "键名2": -1})   1为升序,-1为降序

  限制输出

  • limit(n)  实例:db.singer.find().sort({"age":1}).limit(3)
select * from singer order by age asc limit 3
  • skip(n)  实例:db.singer.find().sort({"age":1}).skip(3).limit(2)
select * from singer order by age asc limit 3,2

  

2.聚合 aggregate

  聚合主要用于计算数据,类似sql中的sum()、avg()

  语法:db.集合名称.aggregate( [{管道:{表达式}}] )

  管道:管道一般用于将当前命令的输出结果作为下一个命令的输入,在mongodb中,管道具有同样的作用,文档处理完毕后,通过管道进行下一次处理

  表达式:处理输入文档并输出

  

  2.1 常用表达式

  • $sum:计算总和,$sum:1同count表示计数
  • $avg:计算平均值
  • $min:获取最小值
  • $max:获取最大值
  • $push:在结果文档中插入值到一个数组中
  • $first:根据资源文档的排序获取第一个文档数据
  • $last:根据资源文档的排序获取最后一个文档数据

  2.2 聚合示例

  • $group  语法:db.集合.aggregate( {$group:{_id:'$字段', $表达式: '$字段'} )  分组统计结果,_id为分组依据,后跟分组字段
db.singer.aggregate({
$group : {
_id:null, //为null表示不分组
总人数:{$sum:1},
平均年龄:{$avg:'$age'}
}
}); db.singer.aggregate({
$group : {
_id:'$sex',
名单:{$push:'$name'} //name对应的值为数组
}
});
  • $match 管道,匹配条件
//满足大于40  并且按性别分组
db.singer.aggregate([
{
$match:{"age":{$gt:40}}
},
{
$group : {
_id:'$sex',
总人数:{$sum:1},
平均年龄:{$avg:'$age'}
}
}
])
  • $project  是否显示某个字段
db.singer.aggregate([
{$match:{"age":{$gt:50}}},
{$project:{_id:0,name:1}}//显示name,不显示_id
])
  • $sort  排序管道
db.singer.aggregate([
{$match:{"age":{$gt:50}}},
{$project:{_id:0,name:1}},//显示name,不显示_id
{$sort:{'age':1}}
])
  • $limit  限制多少条   $skip  跳过多少条
db.singer.aggregate([
{$match:{"age":{$gt:50}}},
{$project:{_id:0,name:1}},//显示name,不显示_id
{$sort:{'age':1}},
{$skip:2},
{$limit:3}
])
  • $unwind  将数组字段进行拆分,然后分成多个document
db.singer.aggregate([
{$match:{"age":{$gt:50}}},
{$unwind:'$works'}
])

  

3.安全

  1.进入管理平台,首先以无密码形式登陆

  2.创建管理员密码

  • 默认没有admin数据库,可以自己添加一个  use admin
  • 添加好数据库以后可以使用命令添加账户,新增的管理员账号会在system.user集合中,类似mysql的user表
db.createUser({user:"admin",pwd:"password", roles:["root"]})

  3.验证密码  db.auth('admin':'password')

  4.重新挂载服务(卸载之前的服务,sc delete mongodb)   --auth 带上验证

mongod --dbpath d:\mongodb\db --logpath d:\mongodb\log\MongoDB.log --install --serviceName "MongoDB" --auth

  5.测试密码是否生效

use admin;
show collections; //无法查看,就说生效了 //验证密码, 必须进入到让你生效的数据库进行验证
db.auth('admin','password');
//再次查看
show collections; //正常显示说明权限生效

  6.为其他数据库添加用户

//先通过身份验证  再进入指定数据库,添加用户
use app1;
db.createUser({user:"app1",pwd:'123456',roles:[{role:'dbOwner',db:'app1']}})

4.主从复制

  4.1 什么是复制

  复制提供了数据的longyu备份,并在多个服务器上存储数据副本,提高了数据的可用性,并可以保证数据安全性,复制还允许从硬件故障和服务中断中恢复数据

  4.2 为什么复制

  • 数据备份
  • 数据灾难恢复
  • 读写分离
  • 高(24*7)数据可用性
  • 无宕机维护
  • 副本集对应程程序是透明

  4.3 复制的工作原理

  • 复制至少需要两个节点A,B...
  • A是主节点,负责处理客户端请求
  • 其他都是从节点,负责复制主节点上的数据
  • 节点常见的搭配方式:一主一从,一主多从
  • 主节点记录在其上的所有操作,从节点定期轮询主节点获取这些操作,然后对自己的数据副本执行这些操作,从而保证从节点的数据和主节点的一致
  • 主节点与从节点进行数据交互保障数据的一致性

  4.4 复制的特点

  • N个节点的集群
  • 任何节点可作为主节点
  • 所有写入操作都在主节点上
  • 自动故障转移
  • 自动恢复

  4.5 设置复制节点

  开始前,最好把之前的MongoDB服务停掉

  (1) 创建数据库目录t1、t2 用于挂起两个MongoDB服务

  (2) 使用如下格式启动mongod,注意replSet的名称一致的,你可以理解成同一集群下

  • mongod --bind_ip 192.168.0.104 --port 27017 --dbpath d:\mongodb\t1 --replSet rs0
  • mongod --bind_ip 192.168.0.104 --port 27017 --dbpath d:\mongodb\t2 --replSet rs0

  (3) 连接主服务器,假如就设置192.168.0.104:27017 设置为主服务器

  • mongo --host 192.168.0.104 --port 27017

  (4) 初始化 rs.initiate()

  (5) 查看当前服务器主从状态 rs.status()

  (6) 添加副本集,也就是指定从服务器  rs.add("192.168.0.104:27018")

  (7)查看添加的从服务器主从状态 rs.status()

  (8) 连接从服务器,查看提示符

  • mongo --host 192.168.0.104 --port 27018

  (9) 向主服务插入数据

  • db.users.insert({'name':'laoliu'})

  (10) 在从服务器上查询  需要注意的是:在从服务器上进行读操作,需要设置rs.slaveOk()

  • db.users.find()

  4.6 其他说明

  • 删除从节点  rs.remove("192.168.0.104:27018")
  • 关闭主服务器后,再重新启动,会发现原来的从服务器变成了主服务器,新启动的服务器(原来的主服务器)变成了从服务器

5.备份与恢复

  5.1 整库备份

  语法:mongodump -h dbhost -d dbname -o dbdirectory

  • -h:服务器地址,也可以指定端口号
  • -d:需要备份的数据库名称
  • -o:备份的数据存储位置,此目录中存放着备份出来的数据

  比如: mongodump -h 127.0.0.1:27017 -d itsource -o d:\output

一篇搞定MongoDB

  5.2 单个collection备份

  语法:mongoexport -h dbhost -d dbname -c collectionname -f collectionKey -o dbdirectory

  • -h: MongoDB所在服务器地址
  • -d: 需要恢复的数据库实例
  • -c: 需要恢复的集合
  • -f: 需要导出的字段(省略为所有字段)
  • -o: 表示导出的文件名

一篇搞定MongoDB

  5.3 整库恢复

  语法:mongorestore -h dbhost -d dbname --dir dbdirectory

  • -h:服务器地址
  • -d:需要恢复的数据库实例
  • --dir:备份数据所在的位置

  比如:mongorestore -h 127.0.0.1:27017 -d itsource2 d:\mongodb\itsource

一篇搞定MongoDB

一篇搞定MongoDB

  5.4 单个collection恢复

  语法:mongoimport -d dbhost -c collectionname --type csv --headerline --file

  • -type: 指明要导入的文件格式,默认json
  • -headerline: 批明不导入第一行,因为第一行是列名,在csv格式和TSV可用
  • -file: 指明要导入的文件路径

一篇搞定MongoDB

6.python操作MongoDB

安装
pip install pymongo

  

import pymongo
import settings
import copy
import time
import threading
from view_info import view_used_info event_obj = threading.Event()
amount = 10000000 if settings.AMOUNT == '千万' else 1000000 def warpper(func):
def inner(*args, **kwargs):
func_name = func.__name__
print('execute %s ......'%func_name)
with open('operation_%s.log'%amount, 'a') as f:
f.write('[operation]%s\n'%func_name)
view_used_info('before', func_name)
event_obj.set()
start_time = time.time()
print('start_time',start_time)
f.write('[**start_time]%s\n'%start_time)
func(*args, **kwargs)
end_time = time.time()
print('end_time',end_time)
f.write('[**end_time]%s\n' % end_time)
event_obj.clear()
view_used_info('after', func_name)
print('spend_time', end_time-start_time)
f.write('[**spend_time]%s\n'%(end_time-start_time))
f.write('='*50 + '\n\n')
return inner class DbConnection: def __init__(self):
self.client = pymongo.MongoClient(settings.MONGODB_HOST, settings.MONGODB_PORT) #127.0.0.1 27017
self.db = self.client[settings.TEST_DB] #"test"
self.coll = self.db[settings.TEST_COLLECTION] #user @warpper
def init_env(self, amount):
insert_data = []
for i in range(amount):
tmp = copy.deepcopy(settings.DOCUMENT_TEMPLATE)
tmp['uid'] = i
insert_data.append(tmp)
self.coll.insert_many(insert_data) @warpper
def insert_one(self):
tmp = copy.deepcopy(settings.DOCUMENT_TEMPLATE)
tmp['uid'] = -1
self.coll.insert_one(tmp) @warpper
def insert_many(self):
insert_data = []
for i in range(5):
tmp = copy.deepcopy(settings.DOCUMENT_TEMPLATE)
tmp['uid'] = -2
insert_data.append(tmp)
self.coll.insert_many(insert_data) @warpper
def insert_10000(self):
insert_data = []
for i in range(10000):
tmp = copy.deepcopy(settings.DOCUMENT_TEMPLATE)
tmp['uid'] = i - 100000
insert_data.append(tmp)
self.coll.insert_many(insert_data) @warpper
def find_one(self):
self.coll.find_one({'uid':-1}) @warpper
def find_many(self):
self.coll.find({'uid':-2}) @warpper
def update_one(self):
self.coll.update_one({'uid': -1}, {'$set': {'log_operation': 'p'*100}}) @warpper
def update_many(self):
self.coll.update_many({'uid': -2}, {'$set': {'log_operation': 'p'*100}}) @warpper
def delete_one(self):
self.coll.delete_one({'uid':-1}) @warpper
def delete_many(self):
self.coll.delete_many({'uid': -2}) @warpper
def drop(self):
self.coll.drop()