1、mongodb的聚合操作
①聚合: 每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
语法:db.集合名称.aggregate({管道:{表达式}})
②常用管道命令:
语法: {管道:{表达式}}
$group
: 将集合中的⽂档分组, 可⽤于统计结果$match
: 过滤数据, 只输出符合条件的⽂档$project
: 修改输⼊⽂档的结构, 如重命名、 增加、 删除字段、 创建计算结果$sort
: 将输⼊⽂档排序后输出$limit
: 限制聚合管道返回的⽂档数$skip
: 跳过指定数量的⽂档, 并返回余下的⽂档
③常⽤表达式:
语法:表达式:'$列名'
$sum
: 计算总和, $sum:1 表示以⼀倍计数$avg
: 计算平均值$min
: 获取最⼩值$max
: 获取最⼤值$push
: 在结果⽂档中插⼊值到⼀个数组中
(1)group分组管道:用来将集合中的文档分组,可用于统计结果
db.stu.aggregate({$group:
{
_id:"$gender",
counter:{$sum:1}
}
}
)
其中注意点:
db.db_name.aggregate
是语法,所有的管道命令都需要写在其中_id
表示分组的依据,按照哪个字段进行分组,需要使用$gender
表示选择这个字段进行分组$sum:1
表示把每条数据作为1进行统计,统计的是该分组下面数据的条数
db.stu.aggregate(
{$group:
{
_id:null,
counter:{$sum:1}
}
}
)
其中注意点:
_id:null
表示不指定分组的字段,即统计整个文档,此时获取的counter
表示整个文档的个数
案例操作:
①统计不同性别的人数
db.stu.aggregate({$group:
{
_id:"$gender",
counter:{$sum:1}
}
})
②统计不同性别的年龄总和
db.stu.aggregate({$group:
{
_id:"$gender",
age_counter:{$sum:"$age"}
}
})
③统计不同性别的平均年龄
db.stu.aggregate({$group:
{
_id:"$gender",
avg_age:{$avg:"$age"}
}
})
④罗列出不同性别的人的名字
db.stu.aggregate({$group:
{
_id:"$gender",
name_list:{$push:"$name"}
}
})
(2)match过滤管道: 过滤数据, 只输出符合条件的⽂档
match和find的区别: $match 操作可以把结果交给下一个管道处理,而find不行。
案例操作
①过滤年龄为18的成员
db.stu.aggregate({$match:
{
age:18
}
})
②过滤年龄为18的成员并按性别分成两组,同时把成员姓名罗列出来
db.stu.aggregate(
{$match:{age:18}},
{$group:{
_id:"$gender",
name_list:{$push:"$name"}
}
}
)
(3)project投影管道:用于修改文档的输入输出结构,例如重命名,增加,删除字段
案例操作:
①仅输出成员的姓名和年龄
db.stu.aggregate(
{$project:{
_id:0,
name:1,
age:1}
}
)
②仅输出成员的姓名和年龄,同时重命名输出
db.stu.aggregate(
{$project:{
_id:0,
"姓名":"$name",
"年龄":"$age"
}
}
)
(4)sort排序管道:用于将输入的文档排序后输出
案例操作:
①查询成员信息,按照年龄升序
db.stu.aggregate(
{$sort:
{age:1}
}
)
②通过性别分组,查询成员信息,按照人数降序
db.stu.aggregate(
{$group:{
_id:"$gender",
counter:{$sum:1}
}
},
{$sort:{
counter:-1
}
}
)
(5)limit限制管道:限制输出的文档数;skip:跳过指定的文档数
案例操作:
先跳过3条文档,限制输出2条文档
db.stu.aggregate(
{$skip:3},
{$limit:2}
)
2、Mongodb的索引操作
**作用:**加快查询速度;进行数据的查重
键入测试数据:
for(i=0;i<100000;i++){
db.t1.insert(
{name:'test'+i,age:i}
)
}
(1)创建索引:db.集合名.ensureIndex({属性:1})
,1表示升序, -1表示降序
db.t1.ensureIndex({name:1})
创建前后查找速度对比:
db.t1.find({name:'test10000'}).explain('executionStats') # 显示查询操作的详细信息
- 创建索引前:
创建索引后:
(2)查看索引:db.集合名.getIndexes()
(3)删除索引:db.集合名.dropIndex({'索引名称':1})
(4)创建唯一索引:db.集合名.ensureIndex({"字段名":1}, {"unique":true})
利用唯一索引可以进行数据去重,当创建了唯一索引以后相同的数据将无法插入
(5)建立复合索引:db.collection_name.ensureIndex({字段1:1,字段2:1})
在进行数据去重的时候,可能用一个域来保证数据的唯一性,这个时候可以考虑建立复合索引来实现。
建立索引需注意:
- 根据需要选择是否需要建立唯一索引
- 索引字段是升序还是降序在单个索引的情况下不影响查询效率,但是带复合索引的条件下会有影响
- 数据量巨大并且数据库的读出操作非常频繁的时候才需要创建索引,如果写入操作非常频繁,创建索引会影响写入速度 例如:在进行查询的时候如果字段1需要升序的方式排序输出,字段2需要降序的方式排序输出,那么此时复合索引的建立需要把字段1设置为1,字段2设置为-1
3、Mongodb的权限管理
目的: 需要设置权限以保证公网运行系统数据安全
管理员: 超级管理员、普通用户
- 用户只能在用户所在数据库登录(创建用户的数据库),包括管理员账号。
- 管理员可以管理所有数据库,但是不能直接管理其他数据库,要先认证后才可以。
配置文件:
(1)创建超级管理员
-
进入mongo shell:
sudo mongod
-
使用admin数据库(超级管理员账号必须创建在该数据库上):
use admin
-
创建超级用户:
db.createUser({"user":"用户名","pwd":"密码","roles":["root"]})
-
退出(exit),以权限认证的方式启动mongodb数据库:
sudo mongod --auth
-
登录验证:
use admin
db.auth('用户名','密码')
注:
- python用户是创建在admin数据库上的所以必须来到admin数据库上进行认证
- 认证成功会返回1,失败返回0
(2)创建普通用户
- 选择需要创建用户的数据库:use test1
- 创建用户:
db.createUser("user":"user1", "pwd":"pwd1", roles:["read"])
创建普通用户user1,该用户在test1上的权限是只读
db.createUser("user":"user1", "pwd":"pwd1", roles:["readWrite"])
创建普通用户user1,该用户在test1上的权限是读写
(3)在admin用户数据库上创建普通用户
#在admin上创建python1用户,python1用户的权限有两个,一个再dbname1上的只读,另一个是在dbname2上的读写
use admin
db.createUser({"user":"python1", "pwd":"python1", roles:[{"role":"read","db":"dbname1"},{"role":"readWrite","db":"dbname2"}
]})
(4)查看已经创建的用户:show users
(5)删除用户
- 进入账号数据所在的数据库:
use 账号所在数据库名
- 删除用户
db.dropUser('用户名')
4、mongodb和python交互
pymongo官方文档或源代码
(1)安装交互模块:pip install pymongo
(2)使用pymongo模块
①无需权限认证的方式创建连接对象以及集合操作对象
from pymongo import MongoClient
client = MongoClient('host',port) # 如果是本地连接host,port参数可以省略
collection = client[db名][集合名]
# collection = client.db名.集合名 # 与上边用法相同
②需要权限认证的方式创建连接对象以及集合操作对象
from pymongo import MongoClient
client = MongoClient('host',port)
# collection = client['db名']['集合名']
# collection = client.db名.集合名 # 与上边用法相同
# 选择一个数据库
db = client['admin']
db.authenticate('用户名','用户密码')
# 选择一个集合
col = client['db名','集合名']
(3)数据的增删改查
①insert()添加数据
# 单条数据添加
collection.insert({一条数据})
# 批量添加数据
collection.insert([{数据一},{数据二}])
例:单条数据的添加
from pymongo import MongoClient
client = MongoClient()
collection = client['amen']['test1']
ret = collection.insert({"name":"哈登","team":"火箭队"})
print(ret)
例:多条数据的添加
from pymongo import MongoClient
client = MongoClient()
collection = client['amen']['test1']
collection.insert([{"name":"威少","team":"火箭队"},{"name":"詹姆斯","team":"湖人队"}])
②find()数据的查找
#单条数据的查找,返回一条数据
collection.findone()
#多条数据的查找,返回一个可迭代对象
collection.find()
例:单条数据的查找
from pymongo import MongoClient
client = MongoClient()
collection = client['amen']['test1']
ret = collection.find_one({"name":"哈登"})
print(ret)
例:多条数据的查找
from pymongo import MongoClient
client = MongoClient()
collection = client['amen']['test1']
rets = collection.find({"team":"火箭队"})
for ret in rets:
print(ret)
③update()更新数据(全文档覆盖或指定键值,更新一条或多条)
语法:collection.update({条件}, {'$set':{指定的kv或完整的一条数据}}, multi=False/True, upsert=False/True)
- $set表示指定字段进行更新
- multi参数:默认为False,表示更新一条; multi=True则更新多条; multi参数必须和$set一起使用
- upsert参数:默认为False; upsert=True则先查询是否存在,存在则更新;不存在就插入
案例1:更新一条数据;全文档覆盖;存在就更新,不存在就插入
案例2:更新多条数据;全文档覆盖;存在就更新,不存在就插入
案例3:更新一条数据;指定键值;存在就更新,不存在就插入
案例4:更新多条数据;指定键值;存在就更新,不存在就插入
④ delete()删除数据
# 删除一条数据
delete_one()
# 删除全部数据
delete_many()
案例1:删除一条数据
案例2:删除全部数据