1、Mongodb的介绍
NoSQL,non-relational sql,非关系型数据库
2、Mongodb的安装和启动
2.1 安装
`sudo apt-get install -y mongodb-org`
2.2 启动
服务器端
查看帮助:`mongdb --help`
服务启动:`sudo service mongod start`
服务停止:`sudo service mongod stop`
服务重启:`sudo service mongod restart`
查看是否启动成功:`ps aux|grep mongod`
配置文件的位置:`/etc/mongodb.conf`
默认端口:`27017`
日志的位置:`/var/log/mongodb/mongod.log`
客户端
启动本地客户端:`mongo`
查看帮助:`mongo --help`
退出:`exit或者ctrl+c`
3、Mongodb的基本操作
3.1 关于database的基础命令
查看当前的数据库:`db`
查看所有的数据库:`show dbs / show databases`
切换数据库:`use db_name`
删除当前的数据库:`db.dropDatabase()`
3.2 关于集合的基础命令
不手动创建集合:
向不存在的集合中第一次加入数据时,集合会被创建出来
手动创建集合:
`db.createCollection(name,options)`
`db.createCollection("stu")`
`db.createCollection("sub",{capped:true,size:10})`
参数capped:默认值为false表示不设置上限,值为true表示设置上限
参数size:当capped值为true时,需要指定此参数,表示上限大小,当文档达到上限时,会将之前的数据覆盖,单位为字节
查看集合:`show collections`
删除集合:`db.集合名称.drop()`
3.3 数据类型
`Object ID`:文档ID
`String`:字符串,最常用,必须是有效的utf8
`Boolean`:存储一个布尔值,true或false
`Integer`:整数可以是32位或64位,这取决于服务器
`Double`:存储浮点值
`Arrays`:数据或列表,多个值存储到一个键
`Object`:用于嵌入式的文档,即一个值为一个文档
`Null`:存储Null值
`Timestamp`:时间戳,表示从1970-1-1到现在的总秒数
`Date`:存储当前日期或时间的UNIX时间格式
3.4 注意点
(1)创建日期语句如下:
参数的格式为YYYY-MM-DD
`new Date("2017-12-30")`
(2)每个文档都有一个数据,为_id,保证每个文档的唯一性
可以自己去设置_id插入文档,如果没有提供,那么MongoDB为每个文档提供了一个独特的_id,类型为objectID
(3)objectID是一个12个字节的十六进制数:
1)前4个字节为当前时间戳
2)接下来3个字节为机器的id
3)接下来的2个字节为MongoDB的服务进程id
4)最后3个字节是简单的增量值
3.5 插入数据
(1)在集合中插入数据:`db.集合名字.insert({"key":"value"})`
(2 )在集合中查找数据:`db.集合名字.find()`
`db.集合名称.inset(document)`
`db.stu.isnert({name:"gj",gender:1})`
`db.stu.insert({_id:"20200507",name:‘gj‘,gender:1})`
插入文档时,如果不指定_id参数,MongoDB会为文档分配一个唯一的ObjectId
3.6 保存
`db.集合名称.save(document)`
如果文档的_id已经存在则修改,如果文档的_id不存在则添加
3.7 查询
`db.集合名称.find(<query>).pretty()`
`db.集合名车.findOne()` 查询满足条件的一个
参数query:查询条件
pretry():美化输出
例子`db.stu.find({age:18}).pretty()`
3.8 更新
`db.集合名称.update(<query>,<update>,{multi:<boolean>})`
参数query:查询条件
参数update:更新操作符
参数multi:可选,默认是false,表示只更新找到的第一条记录,值为true表示把满足条件的文档全部更新
`db.stu.update({name:"hr‘},{name:"mnc"})` 更新一条,所有值都会被替换,只留下name属性和值
`db.stu.update({name:"hr"},{$set:{name:"hys"}})` 更新一条,$set配合update使用,指定一个值来更新
`db.stu.update({},{$set:{gender:0}},{multi:true})` 更新全部,multi必须配合$符号一起使用,否则会无效
注意:“multi update only works with $ operators”
3.9 删除
`db.集合名称.remove(<query>,{justOne:<boolean>})`
参数query:可选,删除的文档的条件
参数justOne:可选,如果设为true或1,则只删除一条,默认为false表示删除多条
4、Mongodb数据查询
4.1 数据查询
(1)方法find():查询
`db.集合名称.find({条件文档})`
(2)方法findOne():查询,只返回第一个
`db.集合名称.findOne({条件文档})`
(3)方法pretty():将结果格式化
`db.集合名称.find({条件文档}).pretty()`
`db.stu.find({age:18}).pretty()`
4.2 比较运算符
(1)等于:默认是等于判断,没有运算符
(2)小于:$lt (less than)
(3)小于等于:$lte (less than equal)
(4)大于:$gt (greater than)
(5)大于等于:$gte (greater than equal)
(6)不等于:$ne
`db.stu.find(age:{$gte:18})` 查找年龄大于等于18的匹配项
4.3 范围运算符
使用“$in”,"$nin"判断是否在某个范围内
例如:查询年龄为18、28或38的学生 `db.stu.find({age:{$in:[18,28,38]}})`
4.4 逻辑运算符
(1)and:在json中写多个条件即可
例如:查询年龄大于或等于18,并且性别为true的学生 `db.stu.find({age:{$gte:18},gender:true})`
(2)or:使用$or,值为数组,数组中每个元素为json
例如:查询年龄大于18,或性别为false的学生 `db.stu.find({$or:[{age:{$gt:18}},{gender:false}]})`
例如:查询年龄大于18或性别为男生,并且姓名是小王 `db.stu.find({$or:[{age:{$gt:18}},{gender:false}],name:"xw"})`
4.5 支持正则表达式
使用//或$regex编写正则表达式
例如:查询姓黄的学生 `db.stu.find({name:/^黄/})`
查询以花结尾的学生姓名 `db.stu.find({name:{$regex:"花$"}})`
4.6 limit和skip
(1)方法limit():用于读取指定数量的文档
`db.集合名称.find().limit(NUMBER)`
例如:查询2条学生信息 `db.stu.find().limit(2)`
(2)方法skip():用于跳过指定数量的文档
`db.集合名称.find().skip(NUMBER)`
例如:跳过前两条数据查询 `db.stu.find().skip(2)`
(3)同时使用 `db.stu.find().limit(4).skip(5)`或`db.stu.find().skip(5).limit(4)`
4.6 自定义查询
使用$where后面写一个函数,返回满足条件的数据
函数语法支持js
例如:查询年龄大于30的学生
```
db.stu.find({
$where:function(){
return this.age>30;
}
})
```
4.7 投影
在查询到的返回结果中,只选择必要的字段
db.集合名称.find({条件},{字段名称:1,..})
参数为字段与值,值为1表示显示,值为0不显示
特殊:对于_id列默认是显示的,如果不显示需要明确设置为0
例如:`db.stu.find({},{_id:0,name:1,gender:1})`
4.8 排序
方法sort(),用于对集合进行排序
db.集合名称.find().sort({字段:1,...})
参数1为升序排列
参数-1为降序排列
例如:根据性别降序,再根据年龄升序 `db.stu.find().sort({gender:-1,age:1})`
4.9 统计个数
方法count()用于统计结果集中文档条数
`db.集合名称.find({条件}).count()`
`db.集合名称.count({条件})`
例如:`db.stu.find({gender:true}).count()`
`db.stu.count({age:{$gt:200},gender:true})`
4.10 消除重复
方法distinct()对数据进行去重
`db.集合名称.distinct("去重字段",{条件})`
例如:`db.stu.distinct("hometown",{age:{$gt:18}})`
6、索引和备份
6.1 备份的语法
`mongodump -h dbhost -d dbname -o dbdirectory`
-h:服务器地址,也可以指定端口号
-d:需要备份的数据库名称
-o:备份的数据存放位置,此目录中存放着备份出来的数据
例如:`mongodump -h 192.168.0.103:27017 -d test -o ~/Desktop/testback`
6.2 数据的恢复
`mongorestore -h dhhost -d dbname --dir dbdirectory`
-h:服务器地址
-d:需要恢复的数据库实例
--dir:备份数据所在位置
`mongorestore -h 192.168.0.100:27017 -d test_back --dir ~/Desktop/testback/test`
7、MongoDB聚合
7.1 聚合aggregate
聚合(aggregate)是基于数据处理的聚合管道,每个文档通过一个由多个阶段(stage)组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果。
db.集合名称.aggregate({管道:{表达式}})
7.2 常用管道命令
在mongodb中,文档处理完毕后,通过管道进行下一次处理
常用管道如下:
`$group`:将集合中的文档分组,可用于统计结果
`$match`:过滤数据,只输出符合条件的文档
`$project`:修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
`$sort`:将输入文档排序后输出
`$limit`:限制聚合管道返回的文档数
`$skip`:跳过指定数量的文档,并返回余下的文档
`$unwind`:将数组类型的字段进行拆分
7.3 表达式
处理输入文档并输入
语法:表达式:‘$列名‘
常用表达式:
`$sum`:计算总合,$sum:1 表示以1倍计数
`$avg`:计算平均值
`$min`:获取最小值
`$max`:获取最大值
`$push`:在结果文档中插入值到一个数组中
`$first`:根据资源文档的排序获取第一个文档数据
`$last`:根据资源文档的排序获取最后一个文档数据
7.4 $group
(1)将集合中的文档分组,可用于统计结果
(2)_id表示分组的依据,使用某个字段的格式为"$字段"
例如:统计男生、女生的总人数
```
db.stu.aggregate(
{$group:{_id:"$gender",counter:{$sum:1}}}
)
```
(3)Group by null
1)将集合中所有文档分为一组
例如:求学生总人数、平均年龄
```
db.stu.aggregate(
{$group:{_id:null,counter:{$sum:1},avAge:{$avg:‘$age‘}}}
)
```
(4)注意点
1)$group对应的字典中有几个键,结果中就有几个键
2)分组依据需要放到_id后面
3)取不同的字段的值需要使用$,如`$gender`,`$age`
4)取字典嵌套的字典中的值的时候用点`.`操作`$_id.country`
5)能够同事按照多个键进行分组`{$group:{_id:{country:"$country",province:"$province"}}`
7.5 $project
修改输入文档的结构,如重命名、增加、删除字段、创建计算结果
例如:查询学生的姓名、年龄
```
db.stu.aggregate(
{$project:{_id:0,name:1,age:1}}
)
```
例如:查询男生、女生人数,输出人数
```
db.stu.aggregate(
{$group:{_id:"$gender",counter:{$sum:1},avg_age:{$avg:"$age"}}},
{$project:{_id:0,counter:1,avg_age:1,gender:"$_id",count:"$count",avg_age:"$avg_age"}}
)
```
7.6 $match
用于过滤数据,只输出符合条件的文档,使用MongoDB的标准查询操作
match是管道命令,能将结果交给后一个管道,但是find不可以
例如:查询年龄大于20的学生
```
db.stu.aggregate(
{$match:{age:{$gt:20}}}
)
```
例如:查询年龄大于20的男生、女生人数
```
db.stu.aggregate(
{$match:{age:{$gt:20}}},
{$group:{_id:"$gender",count:{$sum:1}}},
{$project:{gender:"$_id",_id:0,count:"$count"}}
)
```
7.7 $sort
将输入文档排序后输出
例如:查询男生、女生人数,按人数降序
```
db.stu.aggregate(
{$group:{_id:"$gender",count:{$sum:1}}},
{$sort:{count:-1}}
)
```
7.8 $limit和$skip
$limit
限制聚合管道返回的文档数
例如:查询2条学生信息
```
db.stu.aggregate({$limit:2})
```
$skip
跳过指定数量的文档,并返回余下的文档
例如:查询从第3条开始的学生信息
```
db.stu.aggregate({$skip:2})
```
例如:统计男生、女生人数、按人数升序,取第二条数据
说明:顺序是先写skip,再写limit
```
db.stu.aggregate(
{$group:{_id:"$gender",count:{$sum:1}}},
{$sort:{count:1}},
{$skip:1},
{$limit:1}
)
```
7.9 $unwind
将文档中的某一个数组类型字段拆分成多条,每条包含数组中的一个值
语法:`db.集合名称.aggregate({$unwind:"$字段名称"})`
```
db.test.inset({_id:1,item:"t-shirt",size:["S","M","L"]})
db.test.aggregate({$unwind:"$size"})
```
属性preserveNullAndEmptyArrays值为false表示丢弃属性值为空的文档,为true表示保留属性值为空的文档
用法:
```
db.inventory.aggregate(
{$unwind:{
path:"$字段名称",
preserveNullAndEmptyArrays:<boolean> # 防止数据丢失
}}
)
```
8、创建索引
8.1 创建索引
索引:以提升查询速度
建立索引的语法:
`db.集合.ensureIndex({属性:1})` # 1表示升序,-1表示降序
例如:`db.stu.ensureIndex({name:1})`
测试:插入100000万条数据到数据库中(可以在mongo-cli中使用js语法)
`for(i=0;i<1000000;i++){db.stu.insert({name:"test"+i,age:i})}`
第一次查询时间:(executionTimeMillisEstimate的值)
```
db.stu.find({name:"test100000"})
db.stu.find({name:"test100000"}).explain("executionStats")
```
建立索引后查询时间:
```
db.stu.ensureIndex({name:1})
db.stu.find({name:"test100000"}).explain("executionStats")
```
8.2 索引的使用
(1)在默认情况下索引字段的值可以相同
(2)创键唯一索引(索引的值是唯一的)
`db.stu.ensureIndex({"name":1},{"unique":true})`
(3)建立联合索引
`db.stu.ensureIndex({name:1,age:1})`
(4)查看当前集合的所有索引
`db.stu.getindexes()`
(5)删除索引
`db.stu.dropIndex("索引名称")`
9、Mongo和python交互
9.1 安装pymongo
`pip install pymongo`
9.2 使用代码
class TestMongo(object): def __init__(self): # 实例化一个client,连接到本地mongo服务器 client = MongoClient(host="172.0.0.1",port=27017) # 使用方括号的方式选择数据库和集合 self.collection = client["test"]["stu"] def test_insert(self): #insert接受字典,返回objectId ret = self.collection.insert_one({"name":"test_python_mongo"}) print(ret) def test_insert_many(self): item_list = [{"_id":"{}",‘name‘:"test{}"}.format(i,i) for i in range(10)] # insert_many接受一个列表,列表中为所有需要插入的字典 t = self.collection.insert_many(item_list) # t.inserted_ids为所有插入的id for i in t.inserted_ids: print(i) if __name__=="__main__": obj = TestMonog() obj.test_insert() obj.item_insert_many()