MongoDB--Python

系统 1140 0

MongoDB: 非关系型数据库

    
文件管理阶段:
优点: 
    可以长期保存
    存储大量数据
    使用简单
缺点:
    数据一致性差
    数据大的时候,查找修改不便
    随着时间增长,冗余度大
    
数据库管理阶段:
优点:    
    降低冗余度
    提高增删改查效率
    易扩展
    方便调用和自动化处理
    
缺点:上手相对复杂

数据: 能够输入到计算机中,并被识别处理的信息集合
数据结构:计算机存储、组织数据的方式;
数据库:按照一定数据结构存储管理数据的仓库。 在数据库管理系统管理和控制下,在一定介质上的数据集合
数据库管理系统:管理数据库的软件,用于建立和维护数据库
数据库系统:由数据库管理系统和数据库 ,开发工具等组成的集合

关系型数据库:
    采用关系模型来组织数据结构的数据库(二维表)
    Oracle  DB2  SQLServer Mysql sqLite(Python标准库支持)
优点:     
        容易理解,类似常见的表格
        使用方便,sql语句
        数据一致性高,冗余度低,完整性好
        技术成熟, 可以使用外部链接等比较复杂的操作
        
缺点:    
        不能很好满足高并发需求,每次都需要进行sql语句的解析
        针对海量数据的瞬间爆发,读写性能不足,关系型数据库内部的每部操作需要加锁保证操作的原子性
        数据扩展普遍比非关系困难
        数据一致性高,有时会浪费大量空间

    
非关系型数据库NoSql(Not only Sql):

优点: 
        高并发,大数据读写能力强
        支持分布式,易扩展
        弱化了数据结构,降低了数据的一致性
        
缺点:
        通用性差,没有 像sql那样的一致性操作
        操作灵活,容易混乱
        没有join,有的数据库事物支持等操作
        
Nosql使用场景:
    1, 数据一致性要求低
    2, 数据库 并发处理要求高
    3, 数据库设计时,对大小的估算不确定,需要分布拓展
    4, 给定的数据比较容易建立起Nosql模型
    
    
Nosql分类:
    1,KEY-VALUE : Redis, oracle BDB , Tokyo
    2,列存储数据库:  HBase
    3,文档型数据库:  MongoDB, CouchDB
    4,图形数据库:Neo4j、FlockDB
    
    

MongoDB:
1, C++ 编写的数据库管理系统
2,支持非常丰富的增删改查数据操作
3,支持非常丰富的数据类型
4,使用方便,便于部署,支持分布,容易拓展
5,支持众多的编程语言接口(python, ruby, c++ , c#, PHP)


设计数据库:

微信朋友圈--mysql:
user: id, 昵称, 性别, 电话, 地区;
朋友圈: infoid, 用户id, 文字内容, 图片路径, 视频路径,发布时间,地点,  有效时间
评论: infoid 评论, 点赞数量, 点赞userid


MONGODB:

{
name:zhang, 
age: 20, 
sex:m, 
friendspace:
    [
    {
    id:1,
    content:去台湾插红旗, 
    comment:{
            li:牛逼, 
            wang: 胆儿大, 
            hu:敢去插红旗
            hua: 6666}
    },
    {
    id:2, 
    content: 旅游
    comment:{zhou: 带上我}
    }
    ]
}


MONGOD Install(开源):
自动安装: yum install mangodb
    默认路径:/var/lib/mongodb
    配置文件: /etc/mongodb.conf
    命令集:


手动安装: 
                
PATH=$PATH:/export/servers/mongodb-linux-x86_64-rhel62-3.4.10/bin
export PATH
                
设置数据存储位置:  mongod --dbpath path
指定端口号,--port   默认27017

mongo 进入mongo shell界面
退出界面: quit() 
组成结构: 键值对-->文档 --> 集合 --> 数据库

 


mysql和mongodb对比

mysql:
id            name            age
1            lulijuan        18
2            wanghuan        20
3            fuyalin            20


mongodb:
{
    "id":ObjectId("abcd12345fasds"),   --id由系统自动生成
    "name":"lulijuan"
    "age":18
},
{
    "id":ObjectId("abcd12345fasds"),
    "name":"wanghuan"
    "age":20
},
{
    "id":ObjectId("abcd12345fasds"),
    "name":"fuyalin"
    "age":20
}

-------------------------------------------
mysql            mongodb            含义
-------------------------------------------
database        database        数据库
table            collection        表/集合
column            field            字段/域
row                document        记录/文档
index            index            索引
-------------------------------------------

创建数据库,use db,不存在则创建,并切换;如果已存在则切换;
使用use之后,并不会马上创建,而是插入后才会创建

>  use test
switched to db test

查看数据库: 
> show dbs
admin  0.000GB
local  0.000GB
test   0.000GB
>

数据库名称规则:
1, 原则上满足 utf-8字符
2, 不能是空字符,不能含有空格,点, /  \  \0等
3, 习惯上英文小写
4, 长度不超过64字节
5, 不能使用: admin, local,config等

系统数据库介绍:
admin: 存储用户
local: 存储本地数据
config: 存储分片配置信息

db: mongodb全局变量,显示当前正在使用的数据库;相当于select database();默认为: test如果插入数据,即默认创建test数据库


MONGODB备份和恢复

备份:mongodump -h dbhost -d dbname -o dbdir
    eg: 
        mongodump -h 127.0.0.1 -o /tmp -d test
        2019-06-15T19:44:19.236+0800    writing test.class1 to
        2019-06-15T19:44:19.238+0800    done dumping test.class1 (1 document)

        
    将本机下test 库备份导/tmp文件夹中,会生成一个与库名同名的文件夹
    
    [root@A02-R05-I45-170-J33FE0D test]# ls /tmp/test/
    class1.bson  class1.metadata.json


恢复:
    mongorestore -h : -d dbname  
    eg:
        将备份/tmp/test恢复到本机llj库
        [root@A02-R05-I45-170-J33FE0D test]# mongorestore -h 127.0.0.1:27017 -d llj /tmp/test
    
        
数据库检测:
    mongostat 系统会每秒会检测一次
    insert query update delete getmore command dirty used flushes vsize   res qrw arw net_in net_out conn     time
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0  996M 54.0M 0|0 1|0   158b   46.5k    2 Jun 15 19:55:05.861
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0  996M 54.0M 0|0 1|0   158b   46.4k    2 Jun 15 19:55:06.861
    *0    *0     *0     *0       0     1|0  0.0% 0.0%       0  996M 54.0M 0|0 1|0   157b   46.2k    2 Jun 15 19:55:07.863
    *0    *0     *0     *0       0     2|0  0.0% 0.0%       0  996M 54.0M 0|0 1|0   158b   46.5k    2 Jun 15 19:55:08.860
    
    insert/query/update/delete 每秒增删改查次数
    getmore command: 每秒运行命令的次数
    dirty used flushes 每秒操作磁盘次数
    vsize  res: 使用虚拟内存和物理内存
    
    
mongotop  分别监控每个库,读写时长


删除数据库

先use到对应库下,然后
db.dropDatabase(); 区分大小写,调用dropDatabase()函数完成


集合的创建,切换到需要的库下
db.createCollection(collection_name);
    
or
当向一个 集合插入文档的时候,如果该集合不存在,则自动创建

    > db.class0.insert({'user':'wanghuan'})
    WriteResult({ "nInserted" : 1 })
    >

    
查看集合:
show tables;
show collections;

集合命名规则:
1, 不能为空字符串,不能有\0
2, 不能和关键字重复
3, 不能以system. 开头,这是系统集合的保留前缀

删除集合:

db.collectionsname.drop()
eg:
    tables
    > db.class0.drop()
    true
    >
    > db.class1.drop()
    true

重名名集合
db.collectionName.renameCollection('new_name')


文档:的组织形式

文档的组成形式是bson,类似字典(实际不是字典),也是由key-value对组成
键值对组成文档 ---> 类似python字典
而是bson ---> json --->  JaveScript

文档中,键的命名规则:
1, utf-8字符
2, 不可以\0, 习惯上不用. 和 $
3, 以_开头的多为保留键,自定义KEY一般不以_开头

注意:1,bson 键值对是有序的;
      2, mongodb中严格区分大小写

值:    mongodb的支持数据类型;

MONGODB支持的数据类型:
Type            Value
整型:            整数
布尔bool:        true/false
浮点型:         小数
Arrays            数组类型
Timestamp        时间戳
Date            日期
Object            内部文档
Null            空值
Symbol            特殊字符
String            字符串
Bianry data        二进制字符串
code            代码
regex            正则表达式
ObjectId        ObjectId子串,保证唯一,用于主键

ObjectId:        系统自动为每个文档生成的不重复的主键
                Key:_id
                Value: ObjectId("5d04d6e58734885c8b20206f")
24位 16进制数; 8位文档创建时间 + 6位机器ID + 4位进程ID + 6位计数器


文档特点:
    1, 集合中的文档不一定相同, 不保证数据一致性
    2, 集合中文档结构不一定相同;
    
设计原则:
    1, 集合中文档尽可能描述的数据类似
    2, 同一类文档放在相同集合,不同文档分集合存放
    3, 文档嵌套层次不宜太多
    
插入文档 ---做为文档插入,key可以不加引号
db.collectionName.insert()
> db.wanghuan.insert({'name':'wanghuan', 'age':18, 'sex':'yes'})
WriteResult({ "nInserted" : 1 })

插入多条文档: 
db.collectionName.insert([{},{},{}])

db.collectionName.save()

如果不加_id, 则作用和insert()一致
如果加_id,当没有重复_id值的时候,和insert()一致,如果有重复_id,则update文档
save()方法无法一次插入多个文档

> db.wanghuan.insert([{name:'suhuanhuan', age:18, score:90},{name:'hanxiaojuan', age:22, score:84},{name:'yanqiao', age:19, score:99}])
BulkWriteResult({
    "writeErrors" : [ ],
    "writeConcernErrors" : [ ],
    "nInserted" : 3,
    "nUpserted" : 0,
    "nMatched" : 0,
    "nModified" : 0,
    "nRemoved" : 0,
    "upserted" : [ ]

查找文档 
db.collectionName.find()
> db.wanghuan.find()
{ "_id" : ObjectId("5d05eef59886363f8a94a74c"), "name" : "wanghuan", "age" : 18, "sex" : "yes" }
>


面试问题:关系型数据库和非关系型数据库特点
            mongodb优点:


find(query,field)
功能: 查找所有符合条件的文档
参数: 
query: 筛选条件,相当于where子句
field: 展示的域,相当于select展示部分

field: 传一组键值对, 键表示域名,值表示是否显示,0否,1是

如果某个域给0,则不显示该域,其他域默认显示; 
如果某个域设置1,则显示该域,其他域默认不显示;
_id默认都是显示的
要么都设置0,要么都是1;不可以混用,除_id

    > db.llj.find({},{_id:0,name:1,age:1})
    { "name" : "wanghuan", "age" : 18 }
    { "name" : "wanghuan", "age" : 18 }
    { "name" : "suhuanhuan", "age" : 18 }
    { "name" : "yanqiao", "age" : 18 }
    >

> db.llj.find({},{_id:0,name:0,age:0})
{ "sex" : "yes" }
{ "sex" : "yes" }
{ "sex" : "yes" }
{ "sex" : "yes" }


> db.llj.find({},{name:1,age:1})
{ "_id" : ObjectId("5d05eef59886363f8a94a74c"), "name" : "wanghuan", "age" : 18 }
{ "_id" : 1, "name" : "wanghuan", "age" : 18 }
{ "_id" : 2, "name" : "suhuanhuan", "age" : 18 }
{ "_id" : 3, "name" : "yanqiao", "age" : 18 }
>

query:

> db.llj.find({age:17},{_id:0,name:1,age:1})
{ "name" : "yanqiao", "age" : 17 }
>
>
> db.llj.find({age:18},{_id:0,name:1,age:1})
{ "name" : "wanghuan", "age" : 18 }
{ "name" : "suhuanhuan", "age" : 18 }

findOne()  显示查找结果的第一条数据,类似limit1

> db.llj.findOne({age:18},{})
{
    "_id" : ObjectId("5d05eef59886363f8a94a74c"),
    "name" : "wanghuan",
    "age" : 18,
    "sex" : "yes"
}

操作符:

$ 表名一个特殊字符,表示特殊含义:
比较操作符:
    $eq    等于
    $gt 大于
    $lt    小于
    $ne 不等于
    $gte 大于等于    great equal
    $lte 小于等于    less equal
    $in  包含
    $nin 不包含        not in
    
逻辑操作符:
    $and     逻辑与
    $or        逻辑或
    $not    逻辑非
    $nor    既不也不,表示集合中的条件都不具备
    
    
example:

> db.llj.find({age:{$gt:20}},{_id:0})
{ "name" : "玄冥", "age" : 100, "sex" : "yes" }
{ "name" : "祝融", "age" : 99, "sex" : "yes" }
{ "name" : "东皇", "age" : 1000, "sex" : "no" }
>
>
> db.llj.find({age:{$in:[18,20]}},{_id:0})
{ "name" : "wanghuan", "age" : 18, "sex" : "yes" }
{ "name" : "suhuanhuan", "age" : 18, "sex" : "yes" }
{ "name" : "南落", "age" : 20, "sex" : "no" }
>
>
> db.llj.find({age:{$gte:18,$lte:20}},{_id:0})
{ "name" : "wanghuan", "age" : 18, "sex" : "yes" }
{ "name" : "wanghuan", "age" : 19, "sex" : "yes" }
{ "name" : "suhuanhuan", "age" : 18, "sex" : "yes" }
{ "name" : "南落", "age" : 20, "sex" : "no" }


> db.llj.find({$and:[{age:18},{name:'suhuanhuan'}]},{})
> db.llj.find({$or:[{age:{$eq:100}},{name:'suhuanhuan'}]},{})
> db.llj.find({$or:[{age:{$lte:17}},{age:{$gte:99}}]},{_id:0})

> db.llj.find({sex:{$not:{$eq:'no'}}},{_id:0})
> db.llj.find({age:{$not:{$eq:18}}},{})

> db.llj.find({age:{$nin:[18,17,20]}},{})
> db.llj.find({$and:[{$or:[{age:{$gt:20}},{name:'yanqiao'}]},{sex:'yes'}]},{_id:0})

查看数组中包含travel的文档
> db.wanghuan.find({hobby:'travel'},{})
{ "_id" : ObjectId("5d08832d1d8137d607c20d1c"), "name" : "yanqiao", "hobby" : [ "sleeping", "shopping", "travel" ] }
{ "_id" : ObjectId("5d0883ba1d8137d607c20d1d"), "name" : "suhuanhuan", "hobby" : [ "loveme", "beautiful", "travel" ] }
>

$all 查找数组中,同时包含多个值的文档
$size 查找数组元素个数为指定数量的文档
$slice 数组切片显示 
$exists 判断一个域是否存在
$mod  整除查找,除以某个数余某个数
$type 查找指定类型的文档
类型参考:
    https://docs.mongodb.com/manual/reference/operator/query/type/

    

> db.wanghuan.find({hobby:{$all:['travel','shopping']}},{})
{ "_id" : ObjectId("5d08832d1d8137d607c20d1c"), "name" : "yanqiao", "hobby" : [ "sleeping", "shopping", "travel" ] }

> db.wanghuan.find({hobby:{$size:3}},{})

db.wanghuan.find({},{_id:0, hobby:{$slice:-2}})

查找包含sex域的文档;
> db.wanghuan.find({sex:{$exists:true}},{_id:0})
{ "name" : "wanghuan", "age" : 18, "sex" : "yes" }
{ "name" : "llj", "age" : 20, "sex" : "great" }
{ "name" : "llj", "age" : 20, "sex" : "great" }

查找年龄是奇数的人: {$mod:[2,1]}除以2余1
> db.wanghuan.find({age:{$mod:[2,1]}},{_id:0})


> db.wanghuan.find({_id:{$type:7}})


函数:
distinct()     查看一个集合中,某个域值的覆盖范围
pretty()       将查询结果格式化显示
limit(n)    查询结果显示前n条
skip(n)        显示时跳过前n条
count()        对显示结果计数统计
sort({field:1/-1})        对查找结果,根据指定域进行排序,1升序、-1降序,复合排序,当第一排序项相同的时候按照第二排序项排序


eg:
> db.ming.distinct('skill')
> db.llj.distinct('name')
> db.llj.find().pretty()
> db.ming.find().limit(3)
> db.ming.find().skip(3)    
> db.nanluo.find({sex:'yes'}).count()
> db.nanluo.find({age:{$exists:true}},{_id:0}).sort({age:-1})
> db.nanluo.find({age:{$exists:true}},{_id:0}).sort({age:1, name:1})
> db.nanluo.find({age:{$exists:true}},{_id:0}).sort({age:1}).limit(3)


删除文档

db.collectionName.remove(query,justOne)
功能:    删除指定文档
参数:    query:    筛选条件 ,类似where子句,用法通查询操作
        justOne:    bool值,默认false,表示删除所有匹配条件
                    如果为true,则只删除符合匹配条件一条;
                    

删除存在score域的一条记录
db.wanghuan.remove({score:{exists:true}},true)
删除不存在age域的所有记录
db.wanghuan.remove({age:{$exists:false}})
db.wanghuan.remove({}) 删除集合中所有文档;

修改:

db.collectionName.update(query, update,upsert,multi)
功能: 修改一个文档
参数:    query:     删除要修改的文档,相当于where ,用法同查找
        update:    将数据更新为内容,相当于set,需要使用修改器操作符
        upsert: bool, 默认为false: 如果query的文档不存在则无法修改
                如果为true: 表示如果query的文档不存在,则根据query和update参数插入新文档
        multi: bool值, 默认为false: 如果有多条符合筛选条件的文档,只修改第一条
                如果设置为true,则修改所有符合条件的文档
                
$set:     修改一个域的值
        增加一个域
        删除一个域

$unset: 删除一个域; {$unset:{field:0/1}} 0或者1大都表示删除
$rename:  {$rename:{oldname:newname}}    重命名一个域    
$setOnInsert 如果操作插入新的文档,则补充插入$setOnInsert内容; 如果不插入;如果已经有该记录,则不做操作
$inc        对field进行加减修改,需要是数值型(int,float,负数即可)
$mul        乘法修改器; 乘以某个数(小数,整数,负数皆可)
$min        设定最小值, 如果query域的值小于$min设置的值则不修改,如果大于则改为min值,设置上限
$max        设定最大值,如果query域的值大于$max,则不修改,如果小于max值则修改为max值;设置下限

         
    

                
eg:        
将姓zhang的年龄修改为20
> db.class.update({name:'zhang'},{$set:{age:20}})
姓zhang的年龄修改为20,并且sex改为m
> db.class.update({name:'zhang'},{$set:{age:20, sex:'mm'}})
年龄大于等于10岁的所有人,年龄改为11
> db.class.update({age:{$gte:10}},{$set:{age:11}},false,true)
删除一个域
> db.class.update({name:'wang'},{$unset:{hobby:0, sex:0}})
> db.example.update({}, {$unset: {words:1}}, false, true);
增加一个域
db.class.update({name:'zheng'},{$set:{weapon:'gun'}})
重命名字段名
db.class.update({},{$rename:{sex:'gener'}},false,true)
db.class.update({name:'chen'},{$set:{age:25}, $setOnInsert:{sex:'m',heigh:175}},true)
> db.class.update({age:{$lt:100}},{$inc:{age:-10}},false,true)
db.class.update({},{$mul:{age:0.5}},false,true)
> db.class.update({},{$min:{age:7}},false,true)


MONGODB练习:
1,创建数据库,名字grade
2, 创建集合名字class
3, 集合中插入若干数据,文档格式如下:
    {name:'zhang', age:10,  sex:'m', hobby:['a','b','c']}
    hobby: draw, singing, dancing, basetball, football, pingpong, computer
4, 查找
    a, 查看班级所有人信息
    b, 查看班级中年龄为8岁的学生信息
    c, 查看年龄大于10岁的学生信息
    d, 查看年龄在4-8岁的学生信息
    e, 找到年龄为6岁,且为男生的学生信息
    f, 找到年龄小于7岁,大于10岁的学生
    g, 找到年龄是8岁或者11岁的学生
        db.class.find({age:{$in:[8,11]}})
        db.class.find({$or:[{age:8},{age:11}]})
    h, 找到兴趣爱好有2项的学生
        db.class.find({hobby:{$size:2}})
    i, 找到兴趣爱好有draw的学生
        db.class.find({hobby:'draw'})
    j, 找到既喜欢画画又喜欢跳舞的学生
        db.class.find({hobby:{$all:['draw','dancing']}})
    k, 统计爱好有三项的学生人数
        db.class.find({hobby:{$size:3}})
    l, 找出本班年龄第二大的学生
        db.class.find().sort({age:-1}).skip(1).limit(1)
    m, 查找学生的兴趣范围
         db.class.distinct('hobby')
    n, 将学生按照年龄排序,找到年龄最大的三个
        db.class.find().sort({age:-1}).limit(3)
    o, 删除所有年龄大于12或者小于4岁的学生
        db.class.remove({$or:[{age:{$gt:12}},{age:{$lt:4}}]},false)
    
    
数组修改器:当值为数组的时候,如何进行修改

$push    向数组中添加一项
$pushAll 向数组中添加多项
$each    逐个操作
$position    选择在数组特定位置进行操作必须要与each合用
$sort        对数组排序,必须与each合用;1 表示升序,-1降序
$pull        从数组中删除一个元素
$pullAll    从数组中删除多个元素
$pop        从数组中弹出一个元素,第一个或者最后一个
$addToSet    想数组中插入一个元素,该元素不能和其他元素重复;
数组下标:    使用数组的时候,可以用.index 的方式使用数据的具体某一项;> db.class1.find({'score.0':{$gte:100}})

eg
> db.class1.update({name:'llj'},{$push:{score:60}})
> db.class1.update({name:'wanghuan'},{$pushAll:{score:[101,102]}})
> db.class1.update({name:'suhuanhuan'},{$push:{score:{$each:[103,104]}}},false,true)
> db.class1.update({name:'fantingting'},{$push:{score:{$each:[10,20],$position:1}}})
> db.class1.update({name:'fantingting'},{$push:{score:{$each:[],$sort:1}}})
> db.class1.update({name:'fantingting'}, {$pull:{score:20}})
> db.class1.update({name:'llj'},{$pullAll:{score:[60,91]}})
> db.class1.update({name:'wanghuan'},{$pop:{score:-1}})    弹出第一项
> db.class1.update({name:'wanghuan'},{$pop:{score:1}}) 弹出最后一项
> db.class1.update({name:'wanghuan'},{$addToSet:{score:91}})


类型补充说明:
    mongo中存储时间的格式:ISODate

时间函数: 
    new Date()
    ISODate()
    Date()
    valueOf()     将时间转换为时间戳类似timestamp()
    
方法一: 自动生成当前时间
> db.book.insert({name:'Python入门', date:new Date()})
方法二: 
> db.book.insert({name:'算法结构', date:ISODate()})
方法三: 
> db.book.insert({name:'算法结构', date:Date()})


{ "_id" : ObjectId("5d0b2ed5598f12d353bbc53b"), "name" : "Python入门", "date" : ISODate("2019-06-20T06:59:33.784Z") }
{ "_id" : ObjectId("5d0b2f28598f12d353bbc53c"), "name" : "算法结构", "date" : ISODate("2019-06-20T07:00:56.017Z") }
{ "_id" : ObjectId("5d0b2f90598f12d353bbc53d"), "name" : "算法结构", "date" : "Thu Jun 20 2019 15:02:40 GMT+0800 (CST)" }
>

指定时间:
db.book.insert({name:'爬虫',date:ISODate('2019-06-01 00:00:00')})
db.book.insert({name:'神奇的数学',date:ISODate('20190603')})
> db.book.insert({name:'神奇的数学',date:ISODate('20190603').valueOf()})


null
1, 如果某个域存在 却没有值,可以设置为null
2, 如果某个域不存在可以通过null匹配

> db.class.find({sex:null})
> db.class1.find({date:null})

Object类型:值是一个 文档,文档嵌套

> db.book.insert({name:'pthon Black&white', date:ISODate(), auth:{first:'wang', sec:'change'}})
嵌套文档值的查找
> db.book.find({'auth.first':'wang'})

修改练习:

1, 小红的年龄改为8岁,兴趣爱好改为: dancing, draw
    > db.class.update({name:'zheng'},{$set:{age:8,hobby:['dancing','draw']}})
2, 追加小红的兴趣爱好,singing
    > db.class.update({name:'zhao'},{$push:{hobby:'singing'}})
3, 小王增加兴趣爱好:basketball, 吹牛
    > db.class.update({name:'wang'},{$set:{"name" : "wang", "age" : 10, hobby:['chuiniu','basketball']}})
4, 小李增加兴趣爱好,running, singing, 不要和以前重复
    > db.class.update({name:'li'},{$addToSet:{hobby:{$each:['running','singing','fucking']}}})
5, 班上所有同学年龄+1
    > db.class.update({age:{$exists:1}}, {$inc:{age:1}}, false,true)
6, 删除小明的sex属性
    > db.class.update({name:'wu'},{$unset:{sex:1}}
7, 删除小李兴趣中的第一项
    > db.class.update({name:'li'},{$pop:{hobby:-1}})
8, 小红兴趣中的draw爱好删除
    > db.class.update({name:'zheng'},{$pull:{hobby:'draw'}})


索引:
    指的是建立指定键值即所在文档中存储位置的对照清单,使用索引可以方便我们进行快速查找,减少遍历次数,提高查找效率
    
ensureIndex(field, index_type)    创建索引
参数:    索引类别,索引选项
        field:    域名
        _id域 会自动创建索引
        1表示正向索引,-1表示逆向索引; 想要查找更老的数据还是想要查看更新的数据

查看索引:        
db.class.getIndexes()

删除索引:
dropIndex('index_name') or dropIndex({field_name:1})
dropIndexes() 删除所有索引

复合索引:根据多个字段创建索引

数组索引: 如果对数据域创建索引,俺么表示对数组中每个值俊创建了索引;通过数组中单个值的查询也是索引查询

子文档索引:如果一个域 创建索引,值是一个文档的,则该文档的所有子文档查找,均为索引查找;
    如果对子文档的某个域添加索引,则只能对子文档中的该域查找才会形成索引,子文档其他域的查找不是索引查找
    
覆盖索引,查找时只获取所影项的内容;而不必获取元数据的其他内容;这样就不用连接原来数据,直接返回即可,提高查找效率;

唯一索引:    创建索引时, 索引域的值均不相同,也可以据此限制一个域的值;创建了唯一索引后,不允许再插入该域相同值的文档;
> db.class.ensureIndex({name:1},{unique:true})

稀疏索引(间隙索引):针对有指定域的文档创建索引表,没有该域的文档不会插入到索引表中;
> db.class.ensureIndex({hobby:1},{sparse:true})

索引约束:
    1, 影响数据的插入,删除,更新操作,当数据发生改变的时,索引表必须同步更新
    2, 索引也是需要占用一定空间资源
    
综上:
    1, 当数据库大量的操作是插入,修改,删除操作,而非查询操作时,不适合创建索引
    2, 数据量比较小的时候,也不适合创建索引
    3, 即使适合创建的地方,也不是越多越好;
    
    

> db.class.ensureIndex({name:1})
> db.class.getIndexes()
> db.class.dropIndex("name_1")
> db.class.dropIndex({name:1})
> db.class.dropIndexes()
> db.class.ensureIndex({name:1, age:1})


聚合: 对数据文档进行整理统计

db.collectionName.aggregate()
功能: 聚合函数,配合聚合条件进行数据整理统计
参数: 聚合条件

聚合操作符:
$group  分组操作,类似group by; 和分组操作符配合使用,按什么来分组;
+++++++++++++++++++++++++++++++++++++
分组操作符: 和$group配合

$sum 求和
-----------------------
统计每组个数:
> db.class.aggregate({$group:{_id:'$sex', num:{$sum:1}}})
---------------------------
$group 分组
$sex: 按照sex进行分组
$num: 分组后的域的名字key name
$sum: 求和
1         每统计一个数计为1
----------------------
统计每组年龄和
> db.class.aggregate({$group:{_id:'$sex', num:{$sum:'$age'}}})
------------------------
$avg:    统计平均数

求平均年龄:
> db.class.aggregate({$group:{_id:'$sex', num:{$avg:'$age'}}})
------------------------

$min 分组完求各组的最小值
> db.class.aggregate({$group:{_id:'$sex', num:{$min:'$age'}}})
------------------------
$max: 分组完求各组最大值
> db.class.aggregate({$group:{_id:'$sex', num:{$max:'$age'}}})
------------------------
$first 返回每组文档第一个指定域值
> db.class.aggregate({$group:{_id:'$sex', num:{$first:'$age'}}})
------------------------
$last:     返回每组文档最后一个指定值
> db.class.aggregate({$group:{_id:'$sex', num:{$last:'$age'}}})


+++++++++++++++++++++++++++++++++++++

$project    用于修饰文档的显示结构,规则类似find()的第二个参数
> db.class.aggregate({$project:{_id:0, name:1,age:1}})
> db.class.aggregate({$project:{_id:0, Name:'$name', Age:'$age'}})

$match    过滤数据, 相当于find中的第一个参数query
> db.class.aggregate({$match:{sex:'female'}})
> db.class.aggregate({$match:{age:{$gt:10}}})

$skip 跳过前几条文档
> db.class.aggregate({$skip:5})

$limit    显示几条文档
> db.class.aggregate({$limit:2})

$sort 排序
> db.class.aggregate({$sort:{age:1}})

聚合管道: 将前一个操作的结果给下一个聚合操作继续执行
db.collectionName.aggregate([聚合1,聚合2, 聚合3...])
> db.class.aggregate([{$match:{age:{$gt:10}}},{$limit:3},{$sort:{age:1}}])


聚合练习:
使用grade数据库, 
增加分数域 score:{'chinese':38, 'englist':78, 'math':98}
1, 按照性别分组统计每组人数
    > db.class.aggregate({$group:{_id:'$sex', count:{$sum:1}}})
2, 按照姓名分组,过滤出有重名的同学
    > db.class.aggregate([{$group:{_id:'$name', count:{$sum:1}}},{$match:{count:{$gt:1}}}, {$project:{_id:1}}])
3, 按照每名男生的语文成绩分组
    > db.class.aggregate([{$match:{sex:'m'}},{$group:{_id:'$score.chinese'}}])
    
4, 将女生按照英语成绩分数降序排列
> db.class.aggregate([{$match:{sex:{$in:['f','female']}}}, {$project:{_id:0,name:1,sex:1,english_Score:'$score.englist'}}, {$sort:{english_Score:-1}}])


**************************************************
固定集合, 
定义:mongo中可以创建大小固定的集合,称为固定集合; 固定集合的性能出色,适用于很多场景;
特点: 插入速度快
        顺序查询速度快
        能够淘汰早期数据
        可以控制集合空间
场景:可以轮转更新,缓存, 日志存储等等; 
        
db.createCollection(collectionName, {capped:true,size:100, max:1000})
collectionName: 固定集合名字
size: 设置固定集合大小,kb
max :最多能容纳多少条文档


文件存储:

数据库存储文件的方式:
1, 在数据库中以字符串的方式存储文件在本地的路径
    优点: 解约DB空间
    缺点: 当DB或者文件位置发生变化,即需要更新文档内容
2, 将文件以二进制方式存储在数据库中
    

mongo中,使用GridFS方法 进行大文件存储

GridFS: 是mongodb中大文件存储的一种方案,大于16M的文件为大文件;

在mongodb中,创建两个集合,共同完成对文件的存储
fs.files: 存储文件的基本信息:如文件名,文件类型,文件大小等
fs.chunks: 实际存储文件的内容,以二进制方式分块存储;将大文件分为多个小块,每块占一个chunk

mongofiles -d dbname put filename 文件存储


mongofiles -d gridfs get english.mp3 :文件提取


相同文件的fs.files和fs.chunks 通过相同_id来进行关联
> db.fs.files.find({},{_id:0})
{ "chunkSize" : 261120, "uploadDate" : ISODate("2019-06-23T11:57:08.963Z"), "length" : 20599159, "md5" : "13c794abcdc36e15c84055a1fc87832b", "filename" : "english.mp3" }
{ "chunkSize" : 261120, "uploadDate" : ISODate("2019-06-23T12:11:14.631Z"), "length" : 20599159, "md5" : "13c794abcdc36e15c84055a1fc87832b", "filename" : "chinese.mp3" }
>


大文件存储的优缺点:
优点:存储方便,便于移植,没有对文件个数限制
缺点: 读写效率低,占磁盘空间;


----------------------

python操作Mongo ---> mongodb编程接口:pymongo

安装: sudo pip3 install pymongo

操作步骤:
1, 创建mongo数据库的连接对象
    conn = MongoClient('localhost',27017) 
2, 生成数据库对象: stu库
    db = conn.stu
    
3, 生成集合对象 table name: class0
    my_set = db.class0

4, 增删改查索引聚合操作

5, 关闭对象: conn.close()


插入数据:
insert()
insert_many()
insert_one()
save()

删除数据: 
remove({}, multi = True) multi 默认True,pymongo中默认删除所有符合条件的文档;区别于mongo中的remove;


查找数据: 
find()   查找数据库内容; 同mongo shell find()
        返回一迭代器; 
        
find_one() 只返回一条文档

修改操作:
update()        操作和mongoshell 中相同
update_many()    匹配到多个文档时同时修改
update_one()    只修改匹配到的第一条文档

eg:
my_set.insert({name:'llj', gender:'female', age:18})
my_set.insert({name:'llj', gender:'female', age:18},{})
my_set.remove({name:'llj'}, muulti = False)
my_set.remove() 删除所有文档

cur = my_set.find({'gender':{'$exists':True}},{_id:0})
for i in cur:
    print(i)

for i in cursor.skip(2).limit(3):
        print(i)
        
for i in cursor.sort([('name',1)])
        print(i)

编程中,mongo shell中的null 要用Python中的None替代

wrong: my_set.update_one({age:null},{name:'胤禛'})
right: my_set.update_one({age:None},{name:'胤禛'})
    

    

索引操作

创建单个索引
ensure_index('name')

复合索引创建:
index = my_set.ensure_index([('name',1),('age',-1)])

唯一索引:
index = my_set.ensure_index('field_name', unique = True)

稀疏索引:
index = my_set.ensure_index('name',sparse = True)

查看索引:
list_indexes(), 返回迭代器
for i in my_set.list_indexes()
    print(i)

删除索引:
drop_index(indexName)     删除单个索引
drop_indexes()    删除所有索引
    
    

聚合操作
aggregate([])     

参数与mongo shell中聚合参数写法一致;
返回值: 迭代器,同find()返回值

l = [{'$group':{'_id':'$King', 'count':{'$sum':1}}}
    {'$match':{'count':{'$gt':1}}}]

cursor = my_set.aggregate(l)
for i in cursor:
    print(i)

grid.py

#用来获取数据库中gridfs的存储文件

from pymongo import MongoClient
import gridfs

#创建连接对象
conn = MongoClient('localhost', 27017)
db = conn.grid

#获取gridfs对象
fs = gridfs.GridFS(db)

#所有文件的游标
file = fs.find()
print(files)
print(files.count())

#代表各个文件的对象
for file in files:
    if file.filename == 'abc.mp3':
        with open(file.filename, 'wb') as f:
            while True:
                # file 的read()函数可以获取文件内容
                data = file.read(64)
                if not data:
                    break
                f.write(data)
conn.close()


#save_img.py
#将图片以二进制存储到数据库中

from pymongo import MongoClient
import bson.binary

conn = MongoClient('localhost',27017)
db = conn.file
my_set = db.img

#存储
f = open('img.jpg', 'rb')

#将读取的二进制流变为bson格式二进制的字串
content = bson.bianry.Binary(f.read())

my_set.insert({'filename':'img.jpg', 'data':content})


##提取文件
data = my_set.find_one('filename':'img.jpg')

#通过字典的方式获取内容进行写入即可
with open(data['filename', 'wb']) as f:
    f.write(data['data'])
    
    


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论