
Python 后端开发中数据库操作是绕不开的一环。MongoDB 作为文档型数据库的代表以灵活的 JSON 文档模型、横向扩展能力和丰富的查询语法在大数据量、高并发读写场景下非常常见。要在 Python 项目中操作 MongoDBpymongo 是官方推荐的驱动它封装了连接管理、数据读写、索引操作、聚合查询等功能代码风格也很贴合 Python 习惯。本文会从 MongoDB 的基础概念讲起逐步完成 pymongo 的安装、连接、增删改查、条件筛选、排序分页等操作最后用一个小型学生管理系统把知识点串起来方便你直接复制运行。1. MongoDB 与 pymongo 的核心概念1.1 MongoDB 是什么MongoDB 是一种 NoSQL 文档型数据库它不像 MySQL 或 Oracle 那样用二维表结构来组织数据而是以“文档”为单位存储。每个文档可以理解成一份 JSON 数据里面允许嵌套数组和对象字段也可以不固定。这种设计让 MongoDB 非常接近现代编程语言中的字典或结构体天然适合存储像用户信息、商品详情、日志记录这类结构经常变化的业务数据。对于刚从关系型数据库转过来的开发者可以先看一个简单的对照关系关系型数据库MySQL/OracleMongoDB说明database 数据库database 数据库最外层命名空间table 表collection 集合存放同类文档的容器row 行document 文档一条具体数据column 列field 字段数据中的属性primary key 主键_id 字段默认唯一标识字段的灵活性是 MongoDB 非常重要的特点。在传统关系型数据库里如果表结构已经固定想要加一个字段通常需要执行 ALTER TABLE在 MongoDB 中集合本身不强制字段一致同一条集合里的两条文档可以有不同字段也可以为同一个字段保存不同类型的数据。当然灵活性高也意味着设计时更需要自律否则后期维护成本会上升。1.2 pymongo 在 Python 项目中的作用pymongo 是 MongoDB 官方提供的 Python 驱动程序。它负责把 Python 中的字典对象转换成 MongoDB 需要的 BSON 二进制格式同时也把数据库返回的 BSON 数据还原成 Python 字典。通过 pymongo我们可以在 Python 中完成连接 MongoDB 服务端管理连接池。操作数据库和集合包括创建、删除、统计。执行文档的插入、查询、更新、删除。使用索引、聚合管道、事务等高级能力。监听 MongoDB 的变更流用于构建响应式系统。相比直接通过命令行 mongosh 操作pymongo 的好处是能够和 Python 业务代码无缝集成。比如一个 Web 后端里用户注册后需要把用户数据写入数据库直接在视图函数里调用 pymongo 的方法即可不需要拼接命令行参数。另外pymongo 中有几个需要区分的对象MongoClient 是客户端连接入口负责与 MongoDB 服务端维持连接Database 和 Collection 是在 MongoClient 基础上获取的数据库与集合对象。后续所有数据操作都会围绕这三个对象展开。2. 开发环境准备2.1 安装并启动 MongoDB 服务端在开始写 pymongo 代码之前我们需要一个可用的 MongoDB 服务端。这里可以分为本地安装和云数据库两种方式。本地安装适合学习和离线环境云数据库适合项目联调和生产环境。本地安装 MongoDB 的步骤在不同操作系统上略有区别Windows下载 MongoDB 安装包安装时选择完整模式建议勾选安装 MongoDB Compass 图形工具便于后期查看数据。macOS可以使用 Homebrew执行brew tap mongodb/brew然后执行brew install mongodb-community安装。Linux以 Debian/Ubuntu 为例需要导入 MongoDB 官方 GPG 公钥并配置 apt 源再安装 mongodb-org 系列包。版本方面MongoDB 目前常用的有 4.4、5.0、6.0、7.0 等系列。不同版本的底层存储引擎和部分命令有差异但 pymongo 的核心增删改查 API 保持一致。本文示例以本机默认端口 27017 为例如果你使用的是云数据库只需要把连接地址换成对应的 URI。安装完成后本地启动 mongod 服务mongod --dbpath /data/db --port 27017如果不希望手动指定 dbpath也可以使用系统服务方式启动# macos 或 linux 中使用 brew services 时 brew services start mongodb-community # 直接查看版本确认 mongod 可用 mongod --version如果是 Windows通常会注册成系统服务在服务管理器中确认 MongoDB 服务正在运行。连接地址默认是mongodb://localhost:27017。2.2 创建 Python 环境并安装 pymongo建议为项目创建独立的虚拟环境避免多个项目之间的依赖冲突。Python 3.8、3.9、3.10、3.11 等版本都可以使用 pymongo 4.x 系列。本文示例以 Python 3.10 环境为基础演示如果你的环境不同不影响操作思路。创建虚拟环境python -m venv venv激活虚拟环境# Windows venv\Scripts\activate # macOS / Linux source venv/bin/activate然后安装 pymongopip install pymongo如果下载速度比较慢可以临时使用国内镜像pip install pymongo -i https://pypi.tuna.tsinghua.edu.cn/simple安装完成后检查版本python -c import pymongo; print(pymongo.version)输出类似4.6.2的版本号说明安装成功。实际输出可能不同只要不报错即可。3. 使用 pymongo 连接 MongoDB3.1 MongoClient 连接方式在代码中导入 pymongo 的核心类from pymongo import MongoClient最基础的连接方法如下client MongoClient(mongodb://localhost:27017)也可以使用参数方式连接client MongoClient(hostlocalhost, port27017)如果 MongoDB 设置了用户名和密码需要在 URI 中携带账号信息client MongoClient(mongodb://username:passwordlocalhost:27017/admin?authSourceadmin)这里有一个容易踩坑的点authSource参数表示用户认证数据库。如果用户是在 admin 库下创建的authSource就必须写成admin否则认证会失败。很多初学者在连接时明明用户名密码正确却一直提示Authentication failed多是因为authSource没有配对。另外如果密码中包含、:、/等特殊字符需要对 URI 做 URL 编码否则解析会出错。为了保证连接超时时间可控可以在 MongoClient 中增加serverSelectionTimeoutMS参数client MongoClient( mongodb://localhost:27017, serverSelectionTimeoutMS5000, maxPoolSize20 )serverSelectionTimeoutMS表示服务端选择超时时间如果 MongoDB 没启动这里会快速抛出ServerSelectionTimeoutError而不是让程序无限等待。maxPoolSize是连接池最大连接数用于应对并发场景。3.2 获取数据库和集合对象MongoClient 拿到后有两种方式获取数据库db client[testdb] # 或 db client.testdb两种方式效果一样第一种更灵活因为数据库名可以动态拼接。选择集合对象col db[students] # 或 col db.students需要注意这一行代码并不会真正在 MongoDB 中创建数据库或集合。MongoDB 的推荐方式是“隐式创建”当第一次向不存在的集合写入文档时数据库和集合才会被真正创建。所以你可以放心先获取对象后面插入数据时再自动完成创建。测试连接是否正常try: client.admin.command(ping) print(MongoDB 连接正常) except Exception as e: print(连接失败:, e)如果输出MongoDB 连接正常说明服务端和客户端已经打通接下来可以开始数据操作了。3.3 区分三个对象为了减少后续理解的混乱这里做一个小结MongoClient相当于到 MongoDB 服务端的连接通道一个程序一般只需要创建一个它是线程安全的。Database表示一个数据库相当于关系型数据库中的 database。Collection表示集合相当于表负责具体文档数据的承载。在后续实战代码中我们通常这样创建对象链client MongoClient(mongodb://localhost:27017) db client[school] students db[students]后续所有增删改查都通过students这个对象操作。4. pymongo 增删改查这一节是本文的核心。我们以学生集合students为例学习插入、查询、更新、删除的标准写法。4.1 插入文档4.1.1 插入单条文档使用insert_one参数是一个字典student { name: 张三, age: 20, city: 北京, scores: {math: 90, english: 85} } result students.insert_one(student) print(插入的 _id:, result.inserted_id)执行后MongoDB 会为文档自动生成一个_id字段类型是ObjectId。如果不希望自动生成可以在字典中手动指定_id但要注意唯一性。4.1.2 插入多条文档使用insert_many参数是列表列表中每个元素是一个文档student_list [ {name: 李四, age: 21, city: 上海, scores: {math: 78, english: 92}}, {name: 王五, age: 19, city: 广州, scores: {math: 88, english: 76}}, {name: 赵六, age: 22, city: 深圳, scores: {math: 95, english: 89}}, ] result students.insert_many(student_list) print(插入的 _id 列表:, result.inserted_ids)insert_many会返回一个列表保存每条文档的_id。4.2 查询文档4.2.1 查询第一条匹配的文档使用find_one返回字典或Nonedoc students.find_one({name: 张三}) print(doc)如果你只想看集合中的任意一条可以传空字典doc students.find_one({}) print(doc)4.2.2 查询多条文档使用find返回游标对象可以 for 循环遍历cursor students.find({city: 北京}) for doc in cursor: print(doc)find返回的游标不能像列表一样直接切片所以要限制数量时使用limitcursor students.find({city: 北京}).limit(2)4.2.3 只返回部分字段在关系型数据库中可以通过 SELECT 指定列。在 pymongo 中find的第二个参数是投影条件1表示返回0表示不返回