【Python】MongoDB 基础

45 阅读7分钟

MongoDB 简介:

MongoDB是一个介于关系数据库和非关系数据库之间的产品,是非关系数据库当中功能最丰富,最像关系数据库的。它支持的数据结构非常松散,因此可以存储比较复杂的数据类型。

  • 支持的查询语言非常强大,几乎可以实现类似关系数据库单表查询的绝大部分功能,语法有点类似于面向对象的查询语言;
  • 支持对数据建立索引

特点:

  • 面向集合(Collenction-Orented)

    • 意思是数据被分组存储在数据集中, 被称为一个集合(Collenction)。每个集合在数据库中都有一个唯一的标识名,并且可以包含无限数目的文档。集合的概念类似关系型数据库里的表(table),不同的是它不需要定义任何模式(schema)
  • 2 模式自由(schema-free)

    • 意味着对于存储在 MongoDB 数据库中的文件,我们不需要知道它的任何结构定义。提了这么多次"无模式"或"模式自由",它到是个什么概念呢?例如,下面两个记录可以存在于同一个集合里面: {"welcome" : "Beijing"} {"age" : 25}
  • 3 文档型

    • 意思是我们存储的数据是键-值对的集合,键是字符串,值可以是数据类型集合里的任意类型,包括数组和文档. 我们把这个数据格式称作 “BSON” 即 “Binary Serialized document Notation.”

为什么要使用 NoSQL ?

NoSQL简介:

  • NoSQL,指的是非关系型的数据库。NoSQL有时也称作 Not Only SQL 的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称。
  • NoSQL用于超大规模数据的存储。(例如谷歌或Facebook每天为他们的用户收集万亿比特的数据)。这些类型的数据存储不需要固定的模式,无需多余操作就可以横向扩展。

发展现状(自行查阅资料):

特点:

  • 可以处理超大量的数据

  • 运行在便宜的 PC 服务器集群上 PC

    • 集群扩充起来非常方便并且成本很低,避免了传统商业数据库“sharding”操作的复杂性和成本。
  • 击碎了性能瓶颈

    • NoSQL 的支持者称,通过 NoSQL 架构可以省去将 Web 或 Java 应用和数据转换成 SQL 格式的时间,执行速度变得更快。“SQL并非适用于所有的程序代码”,对于那些繁重的重复操作的数据,SQL 值得花钱。但是当数据库结构非常简单时,SQL 可能没有太大用处
  • 没有过多的操作

    • 虽然 NoSQL 的支持者也承认关系型数据库提供了无可比拟的功能集合,而且在数据完整性上也发挥绝对稳定,他们同时也表示,企业的具体需求可能没有那么复杂
  • 支持者源于社区

    • 因为 NoSQL 项目都是开源的,因此它们缺乏供应商提供的正式支持。这一点它们与大多数开源项目一样,不得不从社区中寻求支持

MongoDB下载与安装

官网下载地址:www.mongodb.com/try/downloa…

image.png

安装方式一:

1、下载好压缩包后将压缩后的文件改名为mongodb,

按住 shift+command+g

然后,输入/usr/local把mongodb放入到该目录中;

2、打开终端

查看电脑是哪一种终端?

若是zsh, 则:

open .zshrc

若是bash终端,则:

open .bash_profile

3、打开后在文本中输入

export PATH=${PATH}:/usr/local/mongodb/bin

command+s保存退出。

4、在终端输入

source .zshrc 

source .bash_profile

使之生效。

可能会遇到的问题(一):

终端中输入 open .bash_profile,提示 .bash_profile does not exist

解决方案:

1、新建一个 .bash_profile

touch .bash_profile

2、然后再去 open .bash_profile,就不会出问题了。

3、在终端输入

source .bash_profile

4、回车使配置生效,接着在终端输入

mongod -version

回车显示 mongodb 版本号,出现下图页面证明配置成功:

image.png

在启动前,在mongodb路径下,创建data和log文件夹,分别用于存在数据和日志。

cd /usr/local/mongodb
mkdir log
mkdir data

image.png

可能会遇到的问题(二):

touch: .bash_profile:拒绝权限:

touch: .bash_profile: Permission denied

解决方案:

在终端中输入:

sudo chown {username} ~/.bash_profile

username,为当前电脑的登录名。

使用方法:

sudo chown zhangsan ~/.bash_profile

然后再输入

source /Users/liangli/.zprofile

保存并生效即可。

安装方式二(尝试失败):

通过 brew 安装,首先要先安装 brew

在终端输入:

/bin/zsh -c "$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrew.sh)"

根据提示进行操作即可;

image.png

安装成功 但还需要重启终端 或者 运行

source /Users/liangli/.zprofile

否则国内地址无法生效。

尝试失败,没查到解决方案,该方法省略。

启动 MongoDB

mongod --fork --dbpath data --logpath log/mongo.log --logappend
mongo

输入 mongo 回车,报错了,zsh: command not found: mongo

这是因为6.0版本之后,没有这个文件。

【解决方案】

www.mongodb.com/try/downloa… 中下载对应版本的 MongoDB Shell image.png

下载完成后,解压缩放在安装 MongoDB 的文件夹下: image.png

然后,在开启了 MongoDB 的服务后,双击 mongosh,即可: image.png

出现下方界面,至此,MongoDB 便连接成功,可以使用了。 image.png

MongoDB 概念解析:

在 MongoDB 中的基本概念是 文档、集合、数据库。 通过对比 SQL,便于理解 MongoDB 中的一些基本概念。 image.png

MongoDB 三要素:

  • 数据库:一个集合的物理容器,一个数据库可以包含多个文档(一个服务器通常有多个数据库。)
  • 文档:关系型数据库中的一行。文档是一个对象,由键值对构成,是 json 的扩展形式。
  • 集合:类似于关系型数据库中表,集合存在于数据库中,集合没有固定的结构,这意味着对集合可以插入不同格式和类型的数据,但通常情况下我们插入集合的数据都会有一定的关联性。

MongoDB 数据类型

  • String:字符串,必须是有效的 UTF-8
  • Boolean:存储一个布尔值,true 或者 false
  • Integer:整数可以是 32位 或 64位,这取决于服务器
  • Double:存储浮点数
  • Arrays:数组或列表
  • Object:嵌入式文档
  • Null:存储 Null 值
  • Timestamp:时间戳, 表示从 1970-1-1 到现在的总秒数
  • Object ID 是一个12字节的十六进制数

MongoDB操作数据库的常用命令

查看所有数据库:

show dbs;

查看现在用的数据库:

(MongoDB 中默认的数据库为 test,如果你没有创建新的数据库,集合将存放在 test 数据库中。)

db

image.png

清屏的命令:

cls 

如果数据不存在,则创建数据库;否则切换到指定数据库。

use maria

注意:刚刚创建的数据库,因为里面还没数据,所以不会显示; 若想显示出来,需要向数据库 maria 中插入一些数据。

db.maria.insert({'name':'manta'})
WriteResult({"nInserted":1})

遇到问题:

DeprecationWarning : collection. 插入已弃用。改为使用 insertOne、insertMany 或 bulkWrite

然后我根据提示,换了方法,操作成功,且不需要 WriteResult,也可以插入数据,并展示我创建的数据库,如下图所示: image.png

删除某个数据库:

需要切换到该数据库 通过 use 和 db 进行切换

db.dropDatabase()

image.png

MongoDB创建集合与查看集合:

手动创建集合之不带关键字:

db.createCollection('集合的名称')

show collections

show tables

image.png

手动创建集合之带关键字:(设置一些属性)

在插入文档时,MongoDB 首先检查固定集合的size字段,然后检查 max 字段。

image.png

db.createCollection('demo002',{capped:true,size:5,max:3})

show tables

整个集合空间大小 5 B, 文档最大个数为 3个。 如果设置的大小小于256就默认是256自动创建集合。

image.png

自动创建集合:

  • 在 MongoDB 中,你不需要创建集合。当你插入一些文档时,MongoDB 会自动创建集合。 image.png

MongoDB 删除集合:

image.png

db.demo003.drop()

MongoDB插入文档(简单的理解就是在集合/表中插入数据)

insert 插入单条数据:

image.png

insert 插入多条数据:

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

image.png

MongoDB查询数据:

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 }])

db.stu.find() 查询数据/可以在括号里面精确查找;

db.stu.find().pretty() 格式化文档打印;

db.stu.find({name:'jerry'}).pretty() 精确查找并格式化打印;

db.stu.findOne() 格式化打印第一条查询的数据;

db.stu.find({age:18})

db.stu.findOne({age:18}) 把满足结果的第一条数据进行返回;

db.stu.find({age:18,gender:true}) 在find中进行多条件查询;

查询之比较运算符:

  • 等于:默认是等于判断,没有运算符

  • 小于:$lt

  • 小于等于:$lte

  • 大于:$gt

  • 大于等于:$gte

举例:
查询年龄大于18的元素:
db.stu.find({age:{$gt:18}})

image.png

查询年龄大于18的元素且hometown是长沙的元素:
db.stu.find({age:{$gt:18},hometown:"长沙"})

查询之范围运算符:

使用in,in,nin判断是否在某个范围内。

查询年龄为18和年龄28的学生:

db.stu.find({age:{$in:[18,28]}})

查询之逻辑运算符:

使用 $or,值为数组,数组中每个元素为 json

查询年龄大于18或者gender为flase的。

db.stu.find({$or:[{age:{$gt:18}},{gender:false}]})

查询之自定义查询:

查询年龄大于18的学生:

db.stu.find({$where:function(){return this.age>18}})

MongoDB 操作查询数据

count()

查出数据求总和 也可以精确查找想要的总和;

db.stu.find().count()
db.stu.count({age:18})
db.stu.find().count({age:18})
db.stu.count()
该方法已被弃用:DeprecationWarning: Collection.count() is deprecated. Use countDocuments or estimatedDocumentCount.

limit()

用于读取指定数量的文档;

db.stu.find().limit()
操作“limit”需要一个整数:MongoInvalidArgumentError: Operation "limit" requires an integer
db.stu.find().limit(3)

skip()

用于跳过指定数量的文档;

db.stu.find().skip(3)

limit() 与 skip()同时使用:

db.stu.find().skip(3).limit(3)

映射:

指定返回的字段,如果为 1 则返回该字段 如果为 0 则除了该字段外所有字段返回。id如果没写会默认返回。

image.png

将 id 去除:

db.stu.find({},{age:1,_id:0})

映射多个值:

比如:只要年龄和性别,不去除id

db.stu.find({},{age:1,gender:1})

排序:

升序:
db.stu.find().sort({age:1})
降序:
db.stu.find().sort({age:-1})

根据 find() 精确查找然后进行排序:

db.stu.find({gender:true}).sort({age:1})

MongoDB 更新文档:

db.集合名称.update({query},{update},{multi:boolean})
参数query:查询条件
参数update:更新操作符
参数multi:可选,默认是false,表示只更新找到的第一条数据,值为true表示把满足条件的数据全部更新
# 该情况下:会改变name并且其他的信息也不会变化;

db.stu.update({name:'张三'},{$set:{name:'张三丰'}})

image.png

更新多条:

比如:将所有的gender变成0 此时会发现 如果没有gender这个属性会进行添加

db.stu.update({},{$set:{gender:0}},{multi:true})

MongoDB 删除文档:

remove()

db.collection.remove(<query>,<justOne>)


query:删除的文档的条件;
justOne:如果设为 true1,则只删除一个文档,如果不设置该参数,或使用默认值 false,则删除所有匹配条件的文档。

删除符合条件的第一条数据:

db.stu.remove({age:18},{justOne:true})

删除符合条件的多条数据:

db.stu.remove({age:18})

删除表/集合:

db.集合名.drop()

小练:

1.查询年龄大于25小于27的name,age
db.persons.find({age:{$gt:25,$lt:27}})

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

3.查询国籍是中国或者美国的学生信息
db.persons.find({$or:[{country:'USA'},{country:'China'}]})
db.persons.find({$or:[{country:'USA'},{country:'China'}]},{country:1}) 数据有点多映射国家

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})
db.persons.find({books:{$all:['MONGODB','PHP']}},{books:1,name:1})


7.查询第二本书是JAVA的学生信息
db.persons.find({},{books:1})
db.persons.find({'books.1':'JAVA'},{name:1,books:1})  'books.1'代表的是索引

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

9.查询出persons中一共有多少国家分别是什么
db.persons.find({},{country:1})v
db.persons.distinct('country')

MongoDB 创建索引:

测试数据集:

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

为什么要用到索引 ?

  • 索引通常能够极大的提高查询的效率,如果没有索引,MongoDB 在读取数据时必须扫描集合中的每个文件并选取那些符合查询条件的记录。
  • 这种扫描全集合的查询效率是非常低的,特别在处理大量的数据时,查询可以要花费几十秒甚至几分钟,这对网站的性能是非常致命的。
  • 索引是特殊的数据结构,索引存储在一个易于遍历读取的数据集合中,索引是对数据库表中一列或多列的值进行排序的一种结构。

创建索引前:

db.demo01.find({name:'person9999'})
# 显示查询操作的详细信息

db.demo01.find({name:'person9999'}).explain('executionStats')

未创建索引前,查找某数据耗时:相当于大海捞针 image.png

如何创建索引:

# 指定 name 为索引值
db.test.ensureIndex({name:1})

创建索引后:

db.demo01.find({name:'person9999'}).explain('executionStats')

image.png

查看所有的索引:

db.demo01.getIndexes()

删除索引:

db.集合名.dropIndex({'索引名称':1})
db.demo01.dropIndex({name:1})
db.demo01.getIndexes()

注意:在3.0.0版本前创建索引的方法为db.collection.ensureIndex(),之后的版本使用了 db.collection.createIndex(),ensureIndex()还能用,但只是 createIndex()的别名。

python与MongoDB交互:

需要安装第三方库 pymongo

pip install pymongo

代码实例: 无需手动创建数据库、数据表/集合,运行代码则自动创建;

import pymongo
from pymongo import MongoClient

# 建立连接
client = MongoClient()

"""与python的交互:增删改查"""


class mongoPython:
    # 初始化
    def __init__(self, HOST, PORT):
        self.HOST = HOST
        self.PORT = PORT
        # 连接
        self.client = MongoClient(HOST, PORT)

    # 插入数据
    def insertData(self):
        # school 代表数据库名称    # teacher 代表表/集合
        # self.client.school.teacher.insert_one({'name': '苏檀儿', 'role': '苏家大小姐'})  # 插入单条数据
        self.client.school.teacher.insert_many([{'name': '宁立恒'}, {'role': '苏家赘婿'}])  # 插入多条数据

    # 查询数据
    def queryData(self):
        try:
            teachers = self.client.school.teacher.find()
            # print(list(teachers), type(teachers))  # <class 'pymongo.cursor.Cursor'>

            # 通过循环,一个个找
            # for item in teachers:
            #     print('查找多条数据:', item['_id'], item['name'])

            teacher = self.client.school.teacher.find_one({'name': '苏檀儿'})
            print(f'查找单条数据', teacher['_id'], teacher['name'])
        except Exception as e:
            print(e)

    # 修改数据
    def setData(self):
        # 修改多条数据
        # self.client.school.teacher.update_many({}, {'$set': {'role': '家佣'}})
        # 修改单条数据
        self.client.school.teacher.update_one({'name': '阿朵'}, {'$set': {'sex': '3333'}})
        # # push() 可向数组的末尾添加一个或多个元素,并返回新的长度
        # self.client.school.teacher.update_one({'name': '檀儿'}, {'$push': {'sdarole': '家佣999'}})

    # 删除数据
    def deleteData(self):
        try:
            # 删除单条数据
            self.client.school.teacher.delete_one({'name': '宁立恒'})
            # 删除多条数据  参数1:查询对象  参数2:用于定义要删除的文档
            query = {'name': '苏檀儿'}
            self.client.school.teacher.delete_many(query)
        except Exception as e:
            print(e)


if __name__ == '__main__':
    mg = mongoPython('localhost', 27017)
    # mg.insertData()
    # mg.queryData()
    mg.setData()
    # mg.deleteData()