3.3 非关系型数据库存储
严格来说,非关系型数据库不是一种数据库,应该是一种数据结构化存储方法的集合,可以是文档或者“键-值对”(Key-Value Pair)等。
相比关系型数据库(比如SQLite),非关系型数据库具有以下优点:
- 格式灵活:存储数据的格式可以是“键-值”(Key-Value)形式、文档形式、图片形式等,使用灵活,应用场景广泛,而关系型数据库则只支持基础类型。
- 速度快:NoSQL可以使用硬盘或者随机存储器作为载体,而关系型数据库只能使用硬盘。
- 高扩展性。
- 成本低:NoSQL数据库部署简单,基本都是开源软件。
同时非关系型数据库与关系型数据库相比有以下缺点:
- 不提供SQL支持,学习和使用成本较高。
- 无事务处理。
- 数据结构相对复杂,复杂查询方面稍微欠缺。
这一节来重点介绍在Python中如何对非关系型数据库MongoDB进行操作。
3.3.1 安装数据库
MongoDB是一个基于分布式文件存储的数据库,由C++语言编写,旨在为Web应用提供可扩展的高性能数据存储解决方案。MongoDB是介于关系数据库和非关系数据库之间的产品,是非关系数据库中功能最丰富、最像关系数据库的。MongoDB是目前流行的NoSQL数据库之一,使用的数据类型为BSON(类似于JSON)。本小节先来介绍如何安装MongoDB数据库。
步骤01 MongoDB提供了可用于32位和64位系统的预编译二进制包,用户可以从MongoDB官网下载安装,MongoDB预编译二进制包下载地址为:
http://dl.mongodb.org/dl/win32/x86_64
注意
在MongoDB 2.2版本后已经不再支持Windows XP系统,最新版本也已经没有了32位系统的安装文件。
步骤02 根据用户所使用的系统下载对应的32位或64位的 .msi文件,下载后双击该文件,按操作提示安装即可。
步骤03 安装过程中,可以通过单击“Custom”按钮来设置安装目录,如图3-19所示。
图3-19 选择安装类型
步骤04 下一步不勾选“install mongoDB compass”选项,否则可能很长时间都在执行安装。MongoDB Compass是一个图形界面管理工具,我们可以自己到官网下载安装,下载地址:https://www.mongodb.com/download-center/compass。
MongoDB将数据目录放在db目录下。但是这个数据目录不会主动创建,我们在安装完成后需要创建它。注意,数据目录应该放在根目录下(如C:\或者D:\等)。
本例我们已经在D盘安装了MongoDB,现在创建一个data的目录,然后在data目录中创建db目录。
步骤05 安装成功之后,下面尝试运行服务器。
为了在“命令提示符”窗口中运行MongoDB服务器,必须在MongoDB目录的bin目录中执行mongod.exe文件。
D:\MongoDB\Server\3.4\bin\mongod --dbpath D:\data\db
如果执行成功,就会输出如图3-20所示的信息。
图3-20 运行服务器
步骤06 在“命令提示符”窗口中运行mongo.exe命令即可连接上MongoDB,命令如下:
D:\MongoDB\Server\3.4\bin\mongo.exe
执行命令之后将打开mongo命令窗口,如图3-21所示。
图3-21 mongo命令窗口
mongo命令窗口是一个JavaScript Shell,用户可以运行一些简单的数学运算,如图3-22所示。
图3-22 在mongo命令窗口中执行数学运算
在该窗口中,使用db命令可以查看当前操作的文档(数据库),如图3-23所示。
图3-23 使用db命令查看当前操作的文档
步骤07 要想在Python中使用MongoDB,还需要安装Python的pymongo模块。由于该模块并不是Python自带的,因此需要单独安装。使用pip安装工具即可安装该模块。
pip install pymongo
安装成功,如图3-24所示。
图3-24 成功安装pymongo模块
之后可以测试是否成功安装,在Python代码中导入pymongo模块,代码如下:
import pymongo
如果没有错误提示,就说明成功安装。
3.3.2 MongoDB概念解析
3.3.1小节成功安装了MongoDB数据库,这一小节来了解关于MongoDB的一些基本概念。
常见的SQL中的概念与MongoDB中对应的概念及其含义如表3-3所示。
表3-3 SQL与MongoDB概念对比
查看表3-3可以发现,MongoDB中一些概念与常规SQL存在不同之处,比如常规的表,MongoDB中叫作集合,常规的记录,MongoDB中叫作文档。关于这些内容将在后续学习中详细为大家介绍。
3.3.3 创建数据库
创建数据库需要使用MongoClient对象,并且指定连接的URL地址和要创建的数据库名。
下面通过示例来说明如何在数据库中创建表。
【示例3-19】创建数据库
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"]
以上代码首先导入pymongo模块,然后连接到本地mongodb服务,最后尝试创建数据库。
注意
在MongoDB中,数据库只有在插入内容后才会创建。也就是说,数据库创建后,要创建集合(数据表)并插入一个文档(记录),数据库才会真正创建。
下面的示例将演示如何读取MongoDB中的所有数据库,并判断指定的数据库是否存在。
【示例3-20】获取所有数据库
import pymongo myclient = pymongo.MongoClient('mongodb://localhost:27017/') dblist = myclient.list_database_names() print(dblist) if "runoobdb" in dblist: print("指定数据库已存在!") else: print("指定数据库不存在!")
以上代码调用list_database_names()方法获取当前所有的数据库,并输出获取结果,然后判断指定的数据库是否存在,并根据结果输出不同的内容。执行代码,其结果如图3-25所示。
图3-25 获取所有数据库
3.3.4 创建集合
MongoDB中的集合类似于SQL中的表。在MongoDB中要创建一个集合,可以使用数据库对象来创建。
【示例3-21】创建集合
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"]
以上代码通过数据库对象来创建集合,执行代码会执行创建集合操作。
注意
在MongoDB中,集合只有在插入内容后才会创建。也就是说,创建集合(数据表)后要再插入一个文档(记录),集合才会真正创建。
3.3.5 插入文档
MongoDB中的一个文档类似于SQL的表中的一条记录。要在集合中插入文档,可以调用insert_one()方法,该方法的参数是字典(name => value,键-值对)。
以下示例向sites集合中插入文档。
【示例3-22】插入文档
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] mydict = { "name": "RUNOOB", "alexa": "10000", "url": "https://www.runoob.com" } x = mycol.insert_one(mydict) print(x)
以上代码通过insert_one()方法将指定的字典数据添加到集合中,并将结果输出。执行以上代码的结果如图3-26所示。
图3-26 插入文档
之所以出现如图3-26所示的结果,是因为insert_one() 方法返回InsertOneResult对象,该对象包含inserted_id属性,它是插入文档的ID值。
【示例3-23】返回插入文档的ID值
import pymongo myclient = pymongo.MongoClient('mongodb://localhost:27017/') mydb = myclient['runoobdb'] mycol = mydb["sites"] mydict = { "name": "Google", "alexa": "1", "url": "https://www.google.com" } x = mycol.insert_one(mydict) print(x.inserted_id)
以上代码通过InsertOneResult对象的inserted_id属性获取插入记录的ID值。执行代码,输出结果如图3-27所示。
图3-27 返回插入文档的ID值
如果我们在插入文档时没有指定 _id, MongoDB就会为每个文档添加唯一的ID。
除了一次插入一个文档之外,集合中还支持一次插入多个文档,调用insert_many()方法即可。该方法的第一个参数是字典列表。insert_many()方法返回InsertManyResult对象,该对象包含inserted_ids属性,该属性保存着所有插入文档的ID值。
【示例3-24】插入多个文档
以上代码定义了一个字典列表,其中包含所有需要一次性插入的文档内容,然后调用insert_many()方法将所有文档内容插入集合中。执行以上代码,其结果如图3-28所示。
图3-28 插入多个文档
3.3.6 查询集合数据
MongoDB支持从所有集合数据中进行查找,调用find和find_one方法即可查询集合中的数据,类似于SQL中的SELECT语句。
如果要查询集合中的一条数据,那么可以调用find_one()方法来查询。
【示例3-25】查询一条数据
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] x = mycol.find_one() print(x)
以上代码调用find_one()方法查询一条数据,并将结果进行输出。执行以上代码,其结果如图3-29所示。
图3-29 查询一条数据
除了可以调用find_one()方法查询一条数据外,还可以调用find()方法查询集合中的所有数据,类似于SQL中的SELECT *操作。
【示例3-26】查询所有数据
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] for x in mycol.find(): print(x)
以上代码调用集合的find ()方法查询所有数据,并通过遍历输出所有结果。执行以上代码,其结果如图3-30所示。
图3-30 查询所有数据
为了获取指定的结果,可以在find()中设置参数来过滤数据,类似于SQL中的SELECT语句的WHERE子句。
【示例3-27】有条件地查询数据
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] myquery = { "name": "Google" } mydoc = mycol.find(myquery) for x in mydoc: print(x)
以上代码调用find ()方法查询数据时定义了字典,用于限定条件,即只返回所有name为Google的文档。执行以上代码,其结果如图3-31所示。
图3-31 限定条件的查询
3.3.7 修改记录
用户可以在MongoDB中调用update_one()方法修改文档中的记录。该方法第一个参数为查询的条件,第二个参数为要修改的字段。如果查找到的匹配数据多于一条,就只修改第一条。
下面的示例将alexa字段的值10000改为12345。
【示例3-28】修改记录
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] myquery = { "alexa": "10000" } newvalues = { "$set": { "alexa": "12345" } } mycol.update_one(myquery, newvalues) print("输出修改后的sites 集合") for x in mycol.find(): print(x)
以上代码调用update_one()方法修改一条记录,参数分别为限制条件的字典与修改为新值的字典。执行以上代码,其结果如图3-32所示。
图3-32 修改记录
从图3-32的执行结果可以看到,相应记录的值已经被修改为新的指定内容。
3.3.8 数据排序
在Python中,使用MongoDB还可以通过查询结果对象的sort()方法对集合数据进行排序。sort() 方法可以指定升序或降序排序。
sort() 方法的第一个参数为要排序的字段,第二个参数指定排序规则:1为升序,-1为降序,默认为升序。
下面的示例将演示对字段alexa按升序排序。
【示例3-29】对集合中的数据进行排序
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] mydoc = mycol.find().sort("alexa") for x in mydoc: print(x)
以上代码对查询的结果调用sort()方法进行排序,其中指定要排序的字段为alexa,并按升序排序。然后通过遍历输出排序后的结果。执行该代码,其结果如图3-33所示。
图3-33 数据排序
查看图3-33的执行结果,对比前面的查询结果可以发现,对alexa按照从小到大的顺序进行了排序,从1、10、100、103、109到12345,从而实现了排序操作。
3.3.9 删除文档
如果数据库集合中的文档不再需要,就可以调用delete_one()方法来删除,该方法的第一个参数为查询对象,指定要删除哪些数据。
【示例3-30】删除文档
import pymongo myclient = pymongo.MongoClient("mongodb://localhost:27017/") mydb = myclient["runoobdb"] mycol = mydb["sites"] myquery = { "name": "Taobao" } mycol.delete_one(myquery) # 删除后输出 for x in mycol.find(): print(x)
以上代码执行集合的delete_one()方法实现删除文档的操作,其中为文档提供的参数为“键-值对”组合,即需要删除的文档的条件是name为Taobao的内容。执行以上代码将会删除指定文档,结果如图3-34所示。
图3-34 删除文档
查看图3-34的执行结果,对比前面的结果,可以发现name为Taobao的文档数据内容被成功删除。