本实训将先介绍MongoDB数据库、PyMongo模块相关知识。然后为“致敬长征”项目创建一个MongoDB数据库及相关集合,以用于数据的存储。
1. MongoDB简介
MongoDB是为快速开发互联网Web应用而设计的数据库系统。它是一个文档型数据库,由 C++ 编写,功能丰富,支持复杂的数据类型,支持数据建立索引,性能高,容易使用,方便部署。其主要特点如下:
- 面向集合存储,方便存储对象类型的数据;
- 支持语言丰富,Python,Java,C++ 等语言;
- 支持完全索引;
- 文件存储格式为 JSON。
MongoDB 由数据库、集合、文档对象组成。传统的关系型数据库以 MySQL 为例,一般是由数据库、表、记录三个层次组成,表1列出了 MongoDB 与 MySQL 的对比。
表1 MongoDB 与 MySQL 区别
MySQL | MongoDB | 描述 |
database | database | 数据库 |
table | collection | 数据库表 / 集合 |
row | document | 数据库行 / 文档 |
column | field | 数据字段列 / 域 |
index | index | 索引 |
2. MongoDB安装
下面以Windows系统为例,演示如何在本地电脑上下载、安装MongoDB数据库。具体步骤如下:
- 登录mongoDB官网,下载免费版mongoDB安装文件,如下面的图1所示。
进入mongoDB官网后,第一步单击导航栏中“Products”;第二步选中“Coummunity Server”选项(如果选择Enterprise Server(企业版),功能强大但需要付费使用),如图2所示;第三步选中右边窗口最下方的“msi”选择“zip”选项;第四步按下“Download”按钮,下载mongoDB数据库,如图3所示。如果下载安装的是MongoDB6或以上版本,则需要另外安装图4中所示的MongoDB Shell来打开客户端。MongoDB5版本则不需要。本实训中使用的是MongoDB5版本。
(2) 下载完成后,可以在下载文件夹中看到压缩文件如图5所示,具体版本号取决于下载时的选择。选中压缩文件,将其解压到合适的文件夹中(如:D:\mongodb5)。 为了以后代码录入时的简便,将子文件夹mongodb-win32-x86_64-windows-5.0.5中的所有内容移动到mongodb5目录下,并将子文件夹mongodb-win32-x86_64-windows-5.0.5删除,如下图6所示。
(3) 在MongoDB5文件夹下创建一个新的文件夹data,然后 在data文件夹下再创建两个新的文件夹:db(用于保存数据库文件)、logs(用于保存日志文件信息),如图7所示:
(4) 进入到MongoDB5下面的bin目录,如下图8所示。
在地址栏中 输入cmd,后按回车键,将打开一个命令行窗口, 在命令行窗口中,输入MongoDB的服务启动命令启动服务,(mongod --dbpath D:\MongoDB5\data\db --logpath D:\MongoDB5\data\logs\mongodb.log --logappend),如图9所示。
备注:服务正常启动后,命令行窗口没有内容输出,只看到光标在不停的闪烁。此时,请确保在没有关闭该命令行窗口的前提下进行后面步骤的操作!!
(5)重新进入到MongoDB5下面的bin目录,在地址栏中 输入cmd后按回车键,再打开另一个命令行窗口。在新打开的命令行窗口中,输入“mongo”命令,启动mongodb客户端,如图10所示。
在mongodb 客户端中输入命令“show dbs”,输入命令后回车,命令窗口中将显示如下输出,如图11所示。此时说明MongoDB 已经配置完成并能正常启动,可以进入下一步的学习。
3. MongoDB的基本操作
MongoDB安装成功后,为了能正常使用MongoDB数据库,需对相关的命令有一定了解。下面将练习MongoDB的基本操作命令的使用。
- 数据库操作
- 用use命令创建一个名为:db_001的数据库,命令及结果如图12 所示。
- 数据库创建完成后,可通过db.createCollection(“集合名称”)创建MongoDB的集合(注:MongoDB的数据库会等到真正写入内容时才创建出来)。如图13所示的命令在数据库中创建一个名为:tb_student的集合:
- 数据库查看(show dbs命令查看所有数据库或db命令查看当前数据库),如图14所示。
- 删除数据库(通过db.dropDatabase(),删除当前数据库),如图15所示。
更多的关于MongoDB数据库的操作方法,可查看相关的官方文档。
- 集合操作
-
注意,因上面的操作已经把db_001数据库删除了。因此,在进行本部分的集合操作前,需再次使用use命令,重新创建数据库db_001。
- 显示创建集合: 通过db.createCollection(‘集合名’, {“选项”}),可显示创建一个集合,如图12所示的命令创建一个tb_student集合。
- 隐式创建集合:可以通过往集合中添加文档的方式隐式创建集合。如图16隐式创建一个名为:tb_course的集合,并用show tables(或show collections) 命令查看已创建的集合。
- 删除集合:使用db.集合名.drop()方法可删除集合,如图17所示。
- 文档操作
-
MongoDB中的数据以文档存储于集合中,文档中数据字段以键值对的方式存储,类似于Python中的字典数据结构。下面分别通过示例练习文档的CRUD(增查改删)相关操作命令。
- 文档插入:可通过insertOne()、 insertMany()、 insert()、save()等方法向集合中添加文档,其中insertOne()用于向集合中添加一个文档,insertMany()可以一次性往集合中添加多条文档。insert()、save()方法也可以实现insertOne()的功能,区别是insert()方法插入文档时,如果集合中已存在该文档,则会抛出duplicate key error 的异常,而save()方法中,如果文档不存在则添加,如果集合中已有该文档,则更新对应的文档。当向集合中添加文档时,如果没有指定“_id”字段,则MongoDB会自动添加一个“_id”的主键字段。相关代码示例如图18所示。
- 文档更新:可通过updateOne()、updateMany()、update() 、replaceOne()等方法向集合中添加文档,其中updateOne ()、replaceOne()用于更新集合中的指定文档,updateMany ()可以一次更新集合中的多条文档,操作示例如图19所示。
查询文档:查询文档通过find()方法实现,find()方法的定义如下:
- db.collection.find(query, projection, options)
- 上式中query参数设置查询过滤条件,projection参数为可选参数,用于指定查询返回的字段,options可选参数用于指定相关的查询选项,如查询的最大等待时间、限定返回的文档数量等。查询示例操作如图20所示。
- 删除文档:可通过deleteOne()、 deleteMany()、remove()等方法实现删除文档的操作,示例代码及运行结果如图21所示。
4. pymongo模块应用
PyMongo是Python3中一个用于连接MongoDB服务器的第三方模块,若要在Python程序中使用MongoDB,需先在Python环境中安装PyMongo。使用pip工具在命令行窗口中安装PyMongo的命令如下:
pip install pymongo
PyMongo模块中提供了4个对象与MongoDB数据库进行交互,分别是MongoClient对象、DataBase对象、Collection对象和Cursor对象。
(1). MongoClient对象
MongoClient对象用于建立与MongoDB数据库的连接,它可以使用如下构造方法进行创建:
MongoClient(host='localhost', port=27017, document_class=dict, tz_aware=False, connect=True, **kwargs)
以上方法中常用参数的含义如下:
- host:表示主机地址,默认为localhost。
- port:表示连接的端口号,默认为27017。
- document_class:表示数据库执行查询操作后返回文档的类型,默认为dict。
建立连接到MongoDB数据库,可以不传入任何参数,说明建立连接到默认主机地址和端口的MongoDB数据库。也可以显式地指定主机地址和端口号。示例如下:
client = MongoClient()
或:
client = MongoClient('localhost', 27017)
(2). DataBase对象
DataBase对象表示一个数据库,可以通过MongoClient对象进行获取。通过上文创建的MongoClient对象client获取数据库,示例如下:
data_base = client.db_name
此外,还可以采用访问字典值的形式获取数据库:
data_base = client['db_name']
需要注意的是,使用以上两种方式获取数据库时,若指定的数据库db_name已经存在,直接访问db_name数据库,否则创建一个数据库db_name。
(3). Collection对象
Collection对象包含一组文档,代表MongoDB数据库中的集合,类似于关系数据库中的表,但它没有固定的结构。PyMongo中使用字典来表示MongoDB数据库的文档,每个文档中都有一个_ id属性,用于保证文档的唯一性,当它们插入到集合中时若未提供_ id,会被MongoDB自动设置独特的_id值。创建Collection对象的方式与创建数据库的方式类似,例如,通过 data_base创建集合test_collection,代码如下:
collection = db.test_collection
也可以采用访问字典值的形式创建Collection对象:
collection = db['test-collection']
Collection对象具备一系列操作文档的方法,这些方法的说明如表2所示。
表2 Collection对象常用方法
方法 | 说明 |
insert_one() | 向集合中插入一条文档 |
insert_many() | 向集合中插入多条文档 |
find_one() | 查询集合中的一条文档。若找到,返回单个文档,否则返回None |
find() | 查询集合中的多条文档。若找到匹配项,则返回一个Cursor对象 |
update_one() | 更新集合中的一条文档 |
update_many() | 更新集合中的多条文档 |
delete_one() | 从集合中删除一条文档 |
delete_many() | 从集合中删除多条文档 |
count_documents(filter) | 根据匹配条件filter统计集合中的文档数量。若传入空字典,则返回所有文档的数量;若传入带有键值对的字典,则返回符合条件的文档数量 |
(4). Cursor对象
Cursor对象是通过Collection对象调用find()方法返回的查询对象,该对象中包含有多条匹配的文档,可结合for循环遍历取出每条文档。
使用PyMongo模块访问MongoDB数据库可分为以下几步:
- 创建一个MongoClient对象,与MongoDB数据库建立连接;
- 使用上个步骤的连接创建一个表示数据库的DataBase对象;
- 使用上个步骤的数据库创建一个表示集合的Collection对象;
- 调用Collection对象的方法,对集合执行增、删、改、查等操作。
PyMongo模块的使用示例如图22所示,图23为示例代码的运行结果。示例代码运行后,通过命令行打开MongoDB客户端,可查询到创建的数据库db_test、集合tb_user,以及添加到集合tb_user中的4个文档,如图24所示。
5. 创建“致敬长征”项目数据库
接下来,将为 “致敬长征”项目创建一个MongoDB数据库,并在数据库创建相应的集合,然后读取示例数据文件中的列表数据并保存到相应的集合中。具体步骤如下:
(1). 创建一个操作MongoDB数据的工具类:在项目根目录下的utils子目录中,创建一个Python脚本文件mongodb_util.py,并编写相应代码,如图25、图26所示。
from pymongo import MongoClient
import json
class MongoProc:
# 构造函数,读取数据库配置文件,初始化数据库连接对象
def __init__(self, conf_file_path):
"""conf_file_path: 数据峰配置文件路径"""
if conf_file_path:
try:
# 从数据库配置文件中读取相关配置
confs = json.load(open(conf_file_path, 'r'))
# 根据配置文件中的数据库服务器地址及端口号,创建到对应服务器的连接实例
self.client = MongoClient(confs["server_url"], confs["server_port"])
self.db = confs["db_name"]
self.confs = confs
except Exception as e:
self.client = MongoClient("127.0.0.1", 27017)
else:
self.client = MongoClient("127.0.0.1", 27017)
# 查询数据库列表
def getDBs(self):
return self.client.list_databases()
# 获取指定数据库中的集合名称列表
def getCollections(self, db_name=None):
"""db_name: 数据昨名称"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
return db.list_collection_names()
# 创建集合
def createColl(self, tbs: list, db_name=None):
"""db_name:数据库名称,tbs:要创建的集合列表"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
try:
for tb in tbs:
db.create_collection(tb)
return True
except Exception as e:
return False
# 删除指定集合
def dropColl(self, tbs: list, db_name=None):
"""db_name:数据库名称, tbs:要创建的集合列表"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
try:
for tb in tbs:
db.drop_collection(tb)
return True
except Exception as e:
return False
# 在数据库指定集合中查询相关文档
def findDoc(self, tb: str, limitnum=20, db_name=None):
"""tb: 要查询的集合名称,limit: 查询的文档限制,db_name: 数据库名称"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
if tb:
tb = db[tb]
return tb.find().limit(limitnum)
else:
return None
# 向指定集合中添加文档
def insertDoc(self, tb: str, docs: list, db_name=None):
"""tb: 集合名称,docs: 要添加的文档列表,db_name:数据库名称"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
if tb:
tb = db[tb]
else:
return "请指定集合名称"
if docs:
try:
return tb.insert_many(docs)
except Exception as e:
return None
# 更新指定集合中的相关文档
def updateDoc(self, tb: str, filter, sets, update_one=False, db_name=None):
"""tb:集合名称,filter:过滤条件,sets:要更新的内容
update_one:是否只史新第一个匹酡的文档,默认为 False,db_name: 数据库名称"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
if tb:
tb = db[tb]
else:
return "请指定集合名称"
try:
if update_one:
return tb.update_one(filter, sets)
else:
return tb.update_many(filter, sets)
except Exception as e:
return None
# 删除指定集合中的相关文档
def deleteDoc(self, tb: str, filter: str, db_name=None):
"""tb:集合名称,filter:过滤条件,db_name:数据库名称"""
if db_name:
db = self.client[db_name]
else:
db = self.client[self.db]
if tb:
tb = db[tb]
else:
return "请指定集合名称"
return tb.delete_many(filter)
(3). 创建数据库初始化模块:在项目根目录下的utils子目录中,创建一个Python脚本文件cz_db_initialize.py,用于初始化“致敬长征”项目的数据库db_cz及集合,并从示例数据文件中读取数据保存到对应的集合中,相关代码如图28所示。
from mongodb_util import MongoProc
import os
from utils.load_data import load_data_from_json_file
class CZProc:
# 构造方法,读入配置文件,创建数据库和相关集合
def __init__(self):
self.mongo_proc = MongoProc("cz_conf.json")
self.mongo_proc.createColl(
tbs=self.mongo_proc.confs["db_colls"],
db_name=self.mongo_proc.db
)
# 将文档数据保存到指定的集合中
def save_docs(self, col, docs):
"""col: 集合名称,docs: 要保存到集合中的文档列表"""
self.mongo_proc.insertDoc(
tb=col,
docs=docs,
db_name=self.mongo_proc.db)
if __name__ == "__main__":
base_path = r"D:\myproj\致敬长征\static\jsons" # jsons文件夹的路径
# 要读取的json文件名(与配置文件中的db_colls相同)
cat_names = ["cz_battle", "cz_hero", "cz_history", "cz_literature", "cz_memorial", "cz_video"]
proc = CZProc() # 创建 CZProc 类的实例
for cat in cat_names: # 循环读取各个json文件,并将相应数据保存到数据库对应的集合中
documents = load_data_from_json_file(os.path.join(base_path, cat + ".json"))
proc.save_docs(col=cat, docs=documents)
(4). 完成前面相应模块的代码编写后,运行cz_db_initialize.py,将会创建“致敬长征”项目的数据库“db_cz”,在数据库创建了六个对应的集合,并将示例数据文件中的数据读取并保存到相应的集合中。程序运行结束后,在MongoDB客户端执行相应的命令查看数据库集合及存储到集合中的文档,查询结果如图29所示。