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的文档数据内容被成功删除。