目录
day04
聚合操作
- 对文档的信息进行整理统计的操作
返回:统计后的文档集合 - 格式:db.collection.aggregate()
- 功能:聚合函数,完成聚合操作
- 参数:聚合条件,配合聚合操作符使用
- 返回:聚合后的结果
- 聚合操作符
- $group 分组聚合 (及其它聚合操作)要配合具体的统计操作符获取结果
操作符 | 含义 | 例子 |
---|---|---|
$sum | 求和 | e.g.求男女生各多少人: db.class2.aggregate({$group:{_id:'$gender',num:{$sum:1}}}) $group:分组,_id:'$gender':按照gender统计,num:{$sum:1}:统计结果,求和每有一个加1 e.g.统计所有男生和女生年龄之和: db.class2.aggregate({$group:{_id:'$gender',num:{$sum:'$age'}}}) |
$avg | 求平均 | e.g.求男生 女生年龄的平均数: db.class2.aggregate({$group:{_id:'$gender',num:{$avg:'$age'}}}) |
$max | 求最大值 | e.g.求男生女生年龄的最大值: db.class2.aggregate({$group:{_id:'$gender',num:{$max:'$age'}}}) |
$min | 求最小值 | e.g.求男生女生年龄的最小值: db.class2.aggregate({$group:{_id:'$gender',num:{$min:'$age'}}}) |
$project | 用于修改文档的展示效果 | e.g.$project值的用法同find() db.class2.aggregate({$project:{_id:0,name:1,age:1}}) e.g.自定义显示的域名 db.class2.aggregate({$project:{_id:0,Name:'$name',Age:'$age'}})
|
$match | 过滤想要的数据 | e.g.过滤年龄大于30的数据,$match值的写法同query db.class2.aggregate({$match:{age:{$ge:30}}}) |
$limit | 显示前几个文档 | e.g.显示前3条 db.class2.aggregate({$limit:3}) |
$skip | 跳过前几个文档显示 | e.g.跳过前2条 db.class2.aggregate({$skip:2}) |
$sort | 排序 | e.g.按年龄升序排序 db.class2.aggregate({$sort:{age:1}}) |
聚合管道
- 将前一个聚合操作产生的结果,交给后一个聚合操作继续使用叫聚合管道
- 格式:db.collection.aggregate([{聚合1},{聚合2},{}...])
- e.g. $match -->$sort -->$project
db.class1.aggregate([{$match:{gender:'m'}},{$sort:{age:1}},{$project:{_id:0}}]) - 聚合练习,使用grade数据库
- 给更多同学添加 内部文档
score:{english:87,chines:76,math:91}
db.class1.update({},{score:{english:87,chines:76,math:91}}) - 按照性别统计每组人数
db.class1.aggregate({$group:{_id:'$sex',num:{$sum:1}}}) - 统计该班中有哪个同学姓名为重名同学
db.class1.aggregate([{$group:{_id:'$name',num:{$sum:1}}},{$match:{num:{$gt:1}}}]) - 统计所有男生的语文成绩,只打印姓名,性别,语文成绩即可
db.class1.aggregate({$match:{sex:'m'}},{$project:{_id:0,name:1,sex:1,'score.chinese':1}}) - 将所有女生按照英语成绩降序排序
db.class1.aggregate([{$match:{sex:''w}},{$sort:{'score.english':-1}}])
- 给更多同学添加 内部文档
文件存储
- 存储路径
将文件放在本地路径(网络路径)下,然后数据库中存储该文件的查找路径
优点:节省数据库空间
缺点:当数据或者文件位置发生变化时文件即丢失 - 将文件转换为二进制,存储文件本身
数据库支持二进制数据格式
将文件转换为二进制格式,然后存入数据库中
优点:数据库和文件绑定,数据库在文件即在
缺点:占用数据库空间大,存取效率低
mongodb存储文件本身
-
前提条件:
- 如果是小文件建议转换二进制直接插入
- 如果是大文件建议使用GridFS方案存储 >16m
- GridFS方案解释
- 在mongodb一个数据库中使用两个集合配合存储文件
- fs.files 用来存储文件的相关信息,为每一个文件创建一个文档,存储文件名,文件大小,存入时间。。。
- fs.chunks用来分块存储文件的实际内容
Binary data 类型数据
- 存储方法
mongofiles -d dbname put file 数据库 要存储的文件 注意:如果数据库不存在自动创建数据库 数据库中会自动创建fs.files fs.chunks两个集合
fs.files文档结构 { "_id" : ObjectId("5b7cdcd769d72e12b4f166d0"), "chunkSize" : 261120, "uploadDate" : ISODate("2018-08-22T03:47:35.381Z"), "length" : 305033, "md5" : "3698b5e762b5b396766aaf9feef7e10d", "filename" : "file.jpg" } fs.chunks文档结构 { "_id" : ObjectId("5b7cdcd769d72e12b4f166d2"), "files_id" : ObjectId("5b7cdcd769d72e12b4f166d0"), "n" : 1, "data" : BinData(0,"tQWR0AR......AG") } * 同一个文件fs.files中的_id值等于fs.chunks中的 files_id域的值
-
提取方法
- 格式:mongofiles -d dbname get file
- GridFS的优缺点
优点 : 存储方便,提供较好的命令支持 和编程接口
缺点 : 存取效率低
游标
mongo shell中获取游标
-
mongo shell 下支持JS代码,可以通过JS获取游标,进而获取数据操作结果
-
e.g.
- var cursor = db.class1.find()
- cursor.next() 获取下一条结果
- cursor.hasNext() 查看是否有下一个对象
通过python操作MongoDB
- pymongo模块 第三方模块
- 安装
sudo pip3 install pymongo
- 操作步骤
- 连接数据库,生成数据库连接对象
conn = pymongo.MongoClient('localhost',27017) - 选择要操作的数据库,生成数据库对象(__setitem__)
db = conn.stu
或者db = conn['stu'] - 获取集合对象
myset = db.class0
或者myset = db['class0'] - 通过集合对象调用mongodb数据库操作函数,增删改查,聚合,索引...
- 关闭数据库连接
conn.close()
- 连接数据库,生成数据库连接对象
- 插入文档
- insert() 插入数据 功能同mongoshell
- insert_many() 插入多条
- insert_one() 插入一条
- save() 插入数据,通过_id可以修改
- 查找操作
- find()
功能:对数据库进行查找
参数:同mongoshell find()
返回值:返回游标对象 - cursor 属性函数
limit()
skip()
count()
sort()
pymongo:sort([('age',1),('name',1)])
mongoshell:sort({age:-1,name:1})
next()
如果通过for 或者next操作了游标对象,在调用limit,skip,sort会报错 - find_one()
用法同mongoshell中findOne()
返回一个字典
- find()
- 修改操作
- update(query,updata,upsert=False,multi=False)
- update_many() 修改多个
- update_one() 修改一个
- 删除操作
- remove(query,multi = True)
功能:删除文档
参数:query 筛选条件
multi:
默认True表示删除所有符合条件的
False只删除一条
- remove(query,multi = True)
- 复合功能函数
find_one_and_delete() 查找并删除from pymongo import MongoClient #创建连接 conn = MongoClient('localhost',27017) #创建数据库对象 db = conn.stu #创建集合对象 myset = db.class4 # print(dir(myset)) #插入操作 # myset.insert({'name':'张铁林','King':'乾隆'}) # myset.insert([{'name':'张国立','King':'康熙'},\ # {'name':'陈道明','King':'康熙'}]) # myset.insert_many([{'name':'唐国强','King':'雍正'},\ # {'name':'陈建斌','King':'雍正'}]) # myset.insert_one({'name':'郑少秋','King':'乾隆'}) # myset.save({'_id':1,'name':'聂远','King':'乾隆'}) #查找操作 # cursor = myset.find({},{'_id':0}) #i为每个文档对应的字典 # for i in cursor: # print(i['name'],'--->',i['King']) # myset = db.class1 #操作符使用引号变为字符串 # cursor = myset.find({'age':{'$gt':30}},{'_id':0}) # cursor.limit(2)#获取前两个文档 # cursor.skip(2) #跳过前两个 # cursor.sort([('age',-1),('name',1)]) #对游标内容排序 # for i in cursor: # print(i) # print(cursor.next()) #获取下一个文档 # dic = {'$or':[{'age':{'$gt':35}},{'gender':'w'}]} # data = myset.find_one(dic,{'_id':0}) # print(data) #修改操作 # myset.update({'name':'张国立'},\ # {'$set':{'king_name':'玄烨'}}) # myset.update({'name':'霍建华'},{'$set':{'King':'乾隆'}},\ # upsert = True) # myset.update({'King':'乾隆'},\ # {'$set':{'king_name':'弘历'}},multi = True) # myset.update_one({'King':'康熙'},\ # {'$set':{'king_name':'爱新觉罗玄烨'}}) # myset.update_many({'King':'雍正'},\ # {'$set':{'king_name':'胤禛'}}) #删除操作 # myset.remove({'King':'康熙'}) # myset.remove({'King':'乾隆'},multi = False) #查找并删除 print(myset.find_one_and_delete({'King':'乾隆'})) #关闭连接 conn.close()
- 索引操作
- ensure_index() 创建索引
- list_indexes() 查看索引
- drop_index() 删除一个索引
- drop_indexes() 删除所有索引
- 聚合操作
- 格式:aggregate([])
参数和mongoshell一样
返回值和find() 函数一样也是得到一个游标对象from pymongo import MongoClient #创建连接 conn = MongoClient('localhost',27017) #创建数据库对象 db = conn['stu'] myset = db['class1'] #删除所有索引 # myset.drop_indexes() #创建索引 # index = myset.ensure_index('name') #创建复合索引 # index = myset.ensure_index([('name',-1),('age',1)]) # print(index) #删除一个索引 # myset.drop_index('name_1') #创建特殊索引 # index = myset.ensure_index('name',name = "myIndex",\ # unique = True,sparse = True) #查看集合中的索引 # for i in myset.list_indexes(): # print(i) myset = db.class4 l = [ {'$group':{'_id':'$King','num':{'$sum':1}}}, {'$match':{'num':{'$gt':1}}} ] cursor = myset.aggregate(l) for i in cursor: print(i) conn.close()
- 格式:aggregate([])
- pymongo进行文件存取操作
GridFS 文件提取
import gridfs- 连接数据库,获取相应的数据库对象
- 通过gridfs.GridFS(db) 获取集合对象 (代表存储文件的两个集合)
- 通过find() 查找文件返回游标
- 通过循环遍历游标获取指定文件对象,read()读取文件内容写入本地
from pymongo import MongoClient #pymongo绑定的模块 import gridfs conn = MongoClient('localhost',27017) db = conn.grid #获取gridfs对象 #fs综合了fs.files fs.chunks两个集合的属性内容 fs = gridfs.GridFS(db) #查文档生产游标 files = fs.find() #获取每一个文件的对象 for file in files: print(file.filename) if file.filename == 'file.jpg': with open(file.filename,'wb') as f: #从数据库读取出来 data = file.read() #写入本地 f.write(data) conn.close()
- 以二进制的方式存取文件
import bson.binaryfrom pymongo import MongoClient import bson.binary conn = MongoClient('localhost',27017) db = conn.images myset = db.img #存储 # f = open('file.jpg','rb') # #转换为mongodb的二进制数据存储形式 # content = bson.binary.Binary(f.read()) # #插入到数据库 # myset.insert({'filename':'file.jpg','data':content}) #提取 data = myset.find_one({'filename':'file.jpg'}) #通过字典获取到数据库内容写入本地 with open(data['filename'],'wb') as f: f.write(data['data']) conn.close()