MangoDB

SQL与NoSQL区别

  • 在SQL中层级关系:数据库->表->数据
  • 在NoSQL中是:数据库->集合->文档

MongoDB优势

  • 无数据结构限制
    • 没有表结构的概念,每条记录可以有完全不同的结构
    • 业务开发方便快捷
  • 大数据量和高性能
    • nosql数据库都具有非常高的读写性能,尤其在大数量下表现优秀
  • 良好的支持
    • 完善的文档
    • 齐全的驱动支持

MongoDB Windows安装与运行

  • Windows安装MongoDB:https://www.cnblogs.com/chy18883701161/p/11100560.html

  • 把MongoDB的bin目录加入到环境变量中

  • 执行

    1
    mongod --dbpath C:\Program Files\MongoDB\Server\4.4\data  # 启动
  • 连接

    • 在环境变量设置好的前提下,使用以下命令mongo就可以进入到mongo的操作终端了
    1
    mongo

MongoDB三元素

  • 三元素:数据库、集合、文档

  • 文档:就是关系型数据库中的一行。文档是一个对象,由键值对构成,是json的扩展形式

    1
    {"name": "abc", "gender": 1}
  • 集合:就是关系型数据库中的表。可以存储多个文档,结构可以不固定。

    {“name”: “abc”, “gender”: 1} {“name”: “abc”, “age”: 18} {“title”: “abc”, “price”: 1}

MongoDB中数据库的基本使用

  • 查看数据库

    • show dbs
  • 切换数据库

    • use 数据库
  • 查看当前的数据库

    • db
  • 删除数据库

    • db.dropDatabase()
  • 会自动创建数据库

    • use 数据库
  • 查看集合

    • show tables/show collections

MongoDB中集合的基础命令

不手动创建集合,向不存在的集合中第一次加入数据时,集合会被创建出来!!!!

手动创建集合 : db.createCollection(name,options)

  • name: 要创建的集合名称
    • 命名规范:
      • 不是空的字符
      • 全部小写
      • 不要有特殊符号
      • 不能使用和系统自带的数据库的名称
      • 最多64字节
  • options: 可选参数, 指定有关内存大小及索引的选项
1
db.createCollection('sub',{capped:true,size:10})
  • 参数capped:默认值为false表示不设置上限,值为true表示设置上限

  • 参数size:当capped值为true时,需要制定此参数。表示上限大小,当文档达到上限时,会将之前的数据覆盖,单位为字节,少于256字节会被定义为256

  • 查看集合

1
show collections
  • 删除集合:db.集合名称.drop()
1
db.xxxx.drop()

MongoDB数据类型

  • String:字符串,必须是有效的UTF-8

  • Boolean:存储一个布尔值,true或者false

  • Integer:整数可以是32位或64位,这取决于服务器

  • Double:存储浮点数

  • Arrays:数组或列表

  • Object:嵌入式文档

  • Null:存储Null值

  • Timestamp:时间戳, 表示从1970-1-1到现在的总秒数

  • Object ID是一个12字节的十六进制数

MongoDB增删改查

  • mongoDB中一张表称为一个集合

MongoDB插入数据

  • db.集合名.insert({}) 数据格式为json,id不能重复,支持多条插入数据库

  • 插入单条数据

    1
    db.sansan.insert({x:1})
  • 插入多条数据

    1
    for(i=3;i<10;i++)db.sansan.insert({x:i})

MongoDB保存 修改

  • 命令:db.集合名称.save(document)

    1
    2
    3
    db.stu.save({_id:ObjectId("5f169b37d74866264ed9a7db"), name:'gj', gender:2}) #有id 进行更改
    db.stu.save({name:'gj', gender:2}) #无ID 直接增加
    db.stu.find()

Mongo查询

  • 测试数据

    1
    2
    3
    4
    5
    6
    7
    db.stu.insert([{"name" : "张三", "hometown" : "长沙", "age" : 20, "gender" : true },
    {"name" : "老李", "hometown" : "广州", "age" : 18, "gender" : false },
    {"name" : "王麻子", "hometown" : "北京", "age" : 18, "gender" : false },
    {"name" : "刘六", "hometown" : "深圳", "age" : 40, "gender" : true },
    {"name" : "jerry", "hometown" : "长沙", "age" : 16, "gender" : true },
    {"name" : "小永", "hometown" : "广州", "age" : 45, "gender" : true },
    {"name" : "老amy", "hometown" : "衡阳", "age" : 18, "gender" : true }])
  • 查询所有数据

    1
    db.stu.find({条件⽂档})
  • pretty():将结果格式化

    1
    db.stu.find({条件⽂档}).pretty()
  • 查询单条数据

    1
    db.stu.findOne({条件⽂档})
  • 有条件的查询数据

    1
    2
    3
    4
    5
    查询x等于100的数据
    db.stu.find({x:100})

    查询x等于100,y等于99的
    db.stu.find({x:100,y:99})
  • 比较运算符

    1
    2
    3
    4
    5
    6
    7
    8
    等于:默认是等于判断,没有运算符
    小于:$lt
    小于等于:$lte
    大于:$gt
    大于等于:$gte

    查询y大于等于18的数据
    db.stu.find({y:{$gte:18}})
  • 范围运算

    1
    2
    使用$in,$nin判断是否在某个范围内查询年龄为18、28的学生
    db.stu.find({age:{$in:[18,28]}})
  • 逻辑运算符

    1
    2
    or:使用$or,值为数组,数组中每个元素为json
    db.stu.find({$or:[{age:{$gt:18}},{gender:false}]})
  • 自定义查询

    • mongo shell 是一个js的执行环境

      使用$where 写一个函数, 返回满足条件的数据

    1
    2
    3
    4
    5
    查询年龄大于30的学生
    db.jerry_collection.find({
    $where:function() {
    return this.age>30;}
    })
  • 映射:指定返回的字段,如果为1则返回改字段,如果为0则除了改字段外所有字段返回。id如果没写会默认返回

    1
    db.sansan.find({},{_id:1})
  • 排序

    1
    2
    3
    4
    5
    按照年龄升序排序
    db.stu().find().sort({age:1})

    按照年龄降序排序
    db.stu().find().sort({age:-1})
  • 修改数据

    1
    db.集合名称.update({query}, {update}, {multi: boolean})
  • 参数query:查询条件

  • 参数update:更新操作符

  • 参数multi:可选,默认是false,表示只更新找到的第一条数据,值为true表示把满足条件的数据全部更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
db.jerry_collection.insert({x:100,y:100,z:100})
{ "_id" : ObjectId("59b297dd8fa0c171faae5bc8"), "x" : 100, "y" : 100, "z" : 100 }

db.jerry_collection.update({x:100},{y:99})
修改后数据变为
{ "_id" : ObjectId("59b297dd8fa0c171faae5bc8"), "y" : 99 }

部分更新
db.jerry_collection.update({x:100},{$set:{y:99}})

如果y:100数据不存在,就插入y:101这条数据,第三个参数为true
db.jerry_collection.update({y:100},{y:101},true)

更新多条
db.jerry_collection.update({y:99},{$set:{y:101}},{multi:true})
  • 删除数据

    1
    2
    3
    db.jerry_collection.remove({条件},{justOne:true})  mongoDB为了防止误删除,条件必须写
    db.jerry_collection.remove() 删除所有数据,索引不会删除
    db.jerry_collection.remove({x:100})
  • 删除表

    1
    db.jerry_collection.drop()
  • 练习

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    测试数据
    var persons = [{
    name:"jim",
    age:25,
    email:"75431457@qq.com",
    c:89,m:96,e:87,
    country:"USA",
    books:["JS","C++","EXTJS","MONGODB"]
    },
    {
    name:"tom",
    age:25,
    email:"214557457@qq.com",
    c:75,m:66,e:97,
    country:"USA",
    books:["PHP","JAVA","EXTJS","C++"]
    },
    {
    name:"lili",
    age:26,
    email:"344521457@qq.com",
    c:75,m:63,e:97,
    country:"USA",
    books:["JS","JAVA","C#","MONGODB"]
    },
    {
    name:"zhangsan",
    age:27,
    email:"2145567457@qq.com",
    c:89,m:86,e:67,
    country:"China",
    books:["JS","JAVA","EXTJS","MONGODB"]
    },
    {
    name:"lisi",
    age:26,
    email:"274521457@qq.com",
    c:53,m:96,e:83,
    country:"China",
    books:["JS","C#","PHP","MONGODB"]
    },
    {
    name:"wangwu",
    age:27,
    email:"65621457@qq.com",
    c:45,m:65,e:99,
    country:"China",
    books:["JS","JAVA","C++","MONGODB"]
    },
    {
    name:"zhaoliu",
    age:27,
    email:"214521457@qq.com",
    c:99,m:96,e:97,
    country:"China",
    books:["JS","JAVA","EXTJS","PHP"]
    },
    {
    name:"piaoyingjun",
    age:26,
    email:"piaoyingjun@uspcat.com",
    c:39,m:54,e:53,
    country:"Korea",
    books:["JS","C#","EXTJS","MONGODB"]
    },
    {
    name:"lizhenxian",
    age:27,
    email:"lizhenxian@uspcat.com",
    c:35,m:56,e:47,
    country:"Korea",
    books:["JS","JAVA","EXTJS","MONGODB"]
    },
    {
    name:"lixiaoli",
    age:21,
    email:"lixiaoli@uspcat.com",
    c:36,m:86,e:32,
    country:"Korea",
    books:["JS","JAVA","PHP","MONGODB"]
    },
    {
    name:"zhangsuying",
    age:22,
    email:"zhangsuying@uspcat.com",
    c:45,m:63,e:77,
    country:"Korea",
    books:["JS","JAVA","C#","MONGODB"]
    }]

    for(var i = 0;i<persons.length;i++){
    db.persons.insert(persons[i])
    }

    var persons = db.persons.find({name:"jim"})
    while(persons.hasNext()){
    obj = persons.next();
    print(obj.books.length)
    }

    题目

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    db.stu.update({name:'张三'},{$set:{name:'zhangsan'}}) 不覆盖后面的内容 
    1.查询年龄大于25小于27的name,age
    db.persons.find({age:{$gt:25,$lt:27}},{name:1,age:1})

    2.查询出不是美国的
    name db.persons.find({country:{$ne:'USA'}},{name:1})

    3.查询国籍是中国或者美国的学生信息
    db.persons.find({$or:[{country:'USA'},{country:'China'}]})

    4.查询语文成绩大于85或者英语成绩大于90的学生信息
    db.persons.find({$or:[{c:{$gt:85}},{e:{$gt:90}}]})

    5.查询出名字中存在"li"的学生信息
    db.persons.find({name:/li/},{name:1})

    6.查询喜欢看MONGODB和PHP的学生
    db.persons.find({books:{$all:['MONGODB','PHP']}},{books:1})

    7.查询第二本书是JAVA的学生信息
    db.persons.find({books:'JAVA'},{books:1}) (在题目中是可以的) db.persons.find({'books.1':'JAVA'},{books:1}) (特殊情况)

    8.查询喜欢的书数量是4本的学生
    db.persons.find({books:{$size:4}},{books:1})

    9.查询出persons中一共有多少国家分别是什么
    db.persons.distinct('country')

聚合

聚合是基于数据处理的聚合管道,每个文档通过一个由多个阶段组成的管道,可以对每个阶段的管道进行分组、过滤等功能,然后经过一系列的处理,输出相应的结果

常用的管道

1
2
3
4
5
$group:将集合中的文档分组,可用于统计结果
$match:过滤数据,只输出符合条件的文档
$sort:将输入文档排序后输出
$limit:限制聚合管道返回的文档书
$skip:跳过指定数量的文档,并返回余下的文档

测试数据

1
2
3
4
5
6
7
db.stu.insert({name:"a", hometown: '东北', age: 20, gender: true})
db.stu.insert({name:"b", hometown: '长沙', age: 18, gender: false})
db.stu.insert({name:"c", hometown: '武汉', age: 18, gender: false})
db.stu.insert({name:"d", hometown: '华山', age: 40, gender: true})
db.stu.insert({name:"e", hometown: '山东', age: 16, gender: true})
db.stu.insert({name:"f", hometown: '江苏', age: 45, gender: true})
db.stu.insert({name:"g", hometown: '大理', age: 18, gender: true})

表达式

  • 语法:表达式:’$列名’
1
2
3
4
5
6
7
$sum: 计算总和, $sum:1 表示以⼀倍计数
$avg: 计算平均值
$min: 获取最⼩值
$max: 获取最⼤值
$push: 在结果⽂档中插⼊值到⼀个数组中
$first: 根据资源⽂档的排序获取第⼀个⽂档数据
$last: 根据资源⽂档的排序获取最后⼀个⽂档数据

$group

将集合中的文档分组,课用于统计结果

  • _id表示分组的依据,使用某个字段的格式为 ‘$字段’
1
2
3
db.students.aggregate(
{$group:{_id:'$gender',count:{$sum:1}}}
)

按照gender分组,获取不同组的平均年龄

1
2
3
db.students.aggregate(
{$group:{_id:'$gender',count:{$sum:1},avg_age:{$avg:"$age"}}}
)

$match

match是管道命令,能将结果交给后一个管道,相当于匹配条件

查询年龄大于20的学生

1
2
3
db.students.aggregate(
{$match:{age:{$gt:20}}}
)

查询年龄大于20的男生,女生人数

1
2
3
4
db.students.aggregate(
{$match:{age:{$gt:20}}},
{$group:{_id:'$gender',count:{$sum:1}}}
)

Mongodb创建索引

1. 为什么mongdb需要创建索引

  • 加快查询速度
  • 进行数据的去重

2. mongodb创建简单的索引方法

  • 语法:db.集合名.ensureIndex({属性:1}),1表示升序, -1表示降序

3. 创建索引前后查询速度对比

测试:插入10万条数据到数据库中

插入数据

1
for(i=0;i<100000;i++){db.test.insert({name:'test'+i,age:i})}

创建索引前

1
2
db.test.find({name:'test9999'})
db.test.find({name:'test9999'}).explain('executionStats') # 显示查询操作的详细信息

创建索引

1
db.test.ensureIndex({name:1})

创建索引后

1
db.test.find({name:'test9999'}).explain('executionStats')

4. 索引的查看

默认情况下_id是集合的索引

查看方式:db.集合名.getIndexes()

5. 删除索引

语法:db.集合名.dropIndex({'索引名称':1})

1
2
db.test.dropIndex({name:1})
db.test.getIndexes()

Mongodb和Python的交互

连接数据库

1
2
3
4
方式一
client = MongoClient()
方式二 指定端口和地址
client = MongoClient('localhost',27017)

新增数据

1
2
3
4
5
import pymongo

mc = pymongo.MongoClient()

mc['san']['sss'].insert({'name':'sansan'}) #数据库 表 数据
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
from pymongo import MongoClient
from datetime import datetime

class TestMongo(object):
def __init__(self):
self.client = MongoClient('mongodb://localhost:27017/')
# 也可以指定连接的集合client['admin']['students']
self.db = self.client['admin']
# print(self.client.database_names())

def add_one(self):
post = {'title':'标题','content':'内容','created_at':datetime.now()}
# db.students students 是表明
res = self.db.students.insert_one(post)
return res

def add_more(self):
data_list = [{"name":"test{}".format(i)} for i in range(5)]
res = self.db.students.insert_many(data_list)
return res


mongo = TestMongo()
res = mongo.add_one()
插入的ID
print(res.inserted_id)

查询数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
from bson.objectid import ObjectId
查询一条数据
def get_one(self):
return self.db.students.find_one()

查询多条数据
def get_more(self):
return self.db.students.find()

根据记录的ID查询数据
def get_from_id(self,id):
return self.db.students.find_one({'_id':ObjectId(id)})

查询一条数据
res = mongo.get_one()
查询多条数据
res = mongo.get_more()
for i in res:
print(i)
根据记录的ID查询数据
res = mongo.get_from_id('5b83e8a1b594c32e8c70c1f7')
print(res)

修改数据

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
修改单条数据
def update(self):
res = self.db.students.update_one({'title':'标题'},{'$set':{'title':'title-2'}})
# 匹配的数据条数
print(res.matched_count)
# 影响的数据条数。
print(res.modified_count)

修改多条
def update_more(self):
res = self.db.students.update_many({},{'$set':{'x':1}})
print(res.matched_count)
print(res.modified_count)
res = self.db.students.update({'x':2},{'$set':{'x':3}},True)

res = mongo.update()
res = mongo.update_more()

删除数据

1
2
3
4
5
6
7
8
9
10
11
12
删除一条
def delete_one(self):
res = self.db.students.delete_one({'title':'title-2'})
print(res.deleted_count)

删除多条
def delete_more(self):
res = self.db.students.delete_many({'x':2})
print(res.deleted_count)

res = mongo.delete_one()
res = mongo.delete_more()

具体练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
import pymongo
from bson.objectid import ObjectId

class MongoData():
def __init__(self,name):
#连接
self.mc = pymongo.MongoClient()
#选择数据库和表
self.db = self.mc['jerry'][name]

def add_one(self,data):

result = self.db.insert_one(data)
return result.inserted_id

def add_many(self,data):

result = self.db.insert_many(data)
return result.inserted_ids

def find_one(self,data=None):
if data==None :
return self.db.find_one()
else:
return self.db.find_one(data)

def find_many(self,data=None):

if data == None:
return self.db.find()
else:
return self.db.find(data)

def updata(self,old,new=None):
r = self.db.update_one(new,{'$set':old})
return r.modified_count

def updatamany(self,new=None):
r = self.db.update_many({},{'$set':old})
return r.modified_count
def remove_one(self,data=None):
r = self.db.delete_one(data)
return r.deleted_count
def remove_many(self,data=None):
r = self.db.delete_many(data)
return r.deleted_count
if __name__ == '__main__':
md = MongoData('student')
# r = md.add_many([{'x':i}for i in range(2)])
# print(r)
# s = md.find_one({'name':'sansan'})
# print(s)
# t = md.find_many({'_id':ObjectId('5fdf52894b31d098362e53d5')})
# print(t)
# for i in t:
# print(i)
# r = md.updata({'name':'sansan'},{'name':'abc'})
# print(r)
# s = md.updatamany({'name':'cde'})
# print(s)
# r = md.remove_one({'name':'cde'})
# print(r)
r = md.remove_many({'name':'cde'})
print(r)