Python3 操作 MongoDB
MongoDB 是一款高性能、文档型 NoSQL 数据库,以灵活的 JSON 格式(BSON)存储数据,非常适合迭代式开发和大数据场景。Python 作为主流编程语言,通过
2. 安装 Python 驱动
通过 pip 安装:
(1)插入单条文档(
(2)插入多条文档(
(1)查询单条文档(
(2)查询多条文档(
(1)更新字段(
(2)替换文档(
pymongo 库可便捷操作 MongoDB。本文从 基础概念→环境搭建→核心操作→进阶技巧 全面讲解 Python3 与 MongoDB 的结合使用。
一、MongoDB 核心概念
在开始 Python 操作前,需先理解 MongoDB 与关系型数据库(如 MySQL)的概念对应关系,避免混淆:
| 关系型数据库(MySQL) | MongoDB | 说明 |
|---|---|---|
| Database(数据库) | Database | 存储数据的顶级容器,一个实例可包含多个数据库 |
| Table(表) | Collection(集合) | 存储文档的集合,无需预定义结构 |
| Row(行) | Document(文档) | 数据的基本单位,格式为 BSON(JSON 扩展) |
| Column(列) | Field(字段) | 文档中的键值对,字段类型灵活可变 |
| Primary Key(主键) | _id 字段 |
文档唯一标识,默认自动生成 ObjectId |
二、环境准备
1. 安装 MongoDB
(1)本地安装(以 Windows 为例)
- 下载地址:MongoDB 官网
- 安装时勾选「Install MongoDB Compass」(可视化工具,可选)
- 验证安装:打开命令行,输入
mongod --version,显示版本信息则成功。
(2)远程 / 云服务(推荐新手)
若本地安装麻烦,可使用云服务(如阿里云 MongoDB、MongoDB Atlas 免费版),直接获取远程连接地址。
2. 安装 Python 驱动 pymongo
pymongo 是 MongoDB 官方推荐的 Python 驱动,支持 Python3.6+。通过 pip 安装:
pip install pymongo # 安装最新版
# 若需指定版本:pip install pymongo==3.12.3
验证安装:
import pymongo
print(pymongo.__version__) # 输出版本号(如 3.12.3),无报错则成功
三、Python 操作 MongoDB 基础
1. 连接 MongoDB
(1)本地无认证连接(默认)
MongoDB 默认端口为
27017,若未设置认证,直接连接:from pymongo import MongoClient
# 方式1:直接指定地址和端口
client = MongoClient("mongodb://localhost:27017/")
# 方式2:通过 host 和 port 参数
# client = MongoClient(host="localhost", port=27017)
# 验证连接:列出所有数据库(非必须,仅用于测试)
print("所有数据库:", client.list_database_names())
(2)带认证连接(生产环境必备)
若 MongoDB 开启了用户名密码认证(推荐),连接时需指定认证数据库(通常为
admin): from pymongo import MongoClient
# 格式:mongodb://用户名:密码@主机:端口/认证数据库?authSource=认证数据库
client = MongoClient("mongodb://root:123456@localhost:27017/?authSource=admin")
# 或分步认证
# client = MongoClient("localhost:27017")
# db_auth = client["admin"] # 认证数据库
# db_auth.authenticate("root", "123456") # 执行认证
(3)远程连接(如 MongoDB Atlas)
远程连接需确保目标 MongoDB 允许外部访问(配置防火墙、bindIp),连接示例:
client = MongoClient(
"mongodb+srv://用户名:密码@集群地址.mongodb.net/?retryWrites=true&w=majority"
) # Atlas 连接格式(带 SSL)
2. 操作数据库与集合
MongoDB 无需手动创建数据库和集合:当首次向不存在的数据库 / 集合写入数据时,会自动创建。
(1)选择 / 创建数据库
# 方式1:通过属性访问(推荐,简洁)
db = client["test_db"] # 选择名为 test_db 的数据库,不存在则自动创建
# 方式2:通过索引访问(适合数据库名含特殊字符)
# db = client.test_db
# 验证:查看当前数据库名
print("当前数据库:", db.name)
(2)选择 / 创建集合
# 方式1:属性访问
collection = db["user"] # 选择名为 user 的集合,不存在则自动创建
# 方式2:索引访问
# collection = db.user
# 验证:列出当前数据库的所有集合
print("当前数据库的集合:", db.list_collection_names())
四、文档(Document)CRUD 操作
文档是 MongoDB 的核心数据单元,格式为 BSON(类似 JSON,支持更多数据类型,如 ObjectId、日期、数组等)。以下以
user 集合为例,讲解增删改查。1. 插入文档(Create)
(1)插入单条文档(insert_one())
返回
InsertOneResult 对象,可通过 inserted_id 获取插入文档的 _id。# 定义文档(Python 字典)
user1 = {
"name": "Alice",
"age": 25,
"gender": "female",
"hobbies": ["reading", "hiking"],
"create_time": pymongo.MongoClient().start_session().start_transaction().current_op().get("startTime") # 或用 datetime
}
# 插入文档
result = collection.insert_one(user1)
# 输出结果
print("插入成功?", result.acknowledged) # True 表示成功
print("插入文档的 _id:", result.inserted_id) # ObjectId 对象(如 ObjectId('60d21b4667d0d8992e610c85'))
(2)插入多条文档(insert_many())
接收列表参数,返回
InsertManyResult 对象,inserted_ids 包含所有插入文档的 _id。user2 = {"name": "Bob", "age": 30, "gender": "male", "hobbies": ["gaming", "coding"]}
user3 = {"name": "Charlie", "age": 28, "gender": "male", "hobbies": ["cooking", "travel"]}
# 插入多条
result = collection.insert_many([user2, user3])
print("插入成功?", result.acknowledged)
print("所有插入文档的 _id:", result.inserted_ids) # 列表形式
2. 查询文档(Read)
pymongo 提供 find_one()(查询单条)和 find()(查询多条),支持条件筛选、排序、分页。(1)查询单条文档(find_one())
- 无参数:返回集合第一条文档
- 带条件:返回符合条件的第一条文档
# 1. 查询第一条文档
first_user = collection.find_one()
print("第一条文档:", first_user)
# 2. 按条件查询(如查询 name = "Alice" 的文档)
alice = collection.find_one({"name": "Alice"})
print("Alice 的信息:", alice)
# 3. 按 _id 查询(需用 ObjectId 类型,不能直接传字符串)
from bson.objectid import ObjectId
user_by_id = collection.find_one({"_id": ObjectId("60d21b4667d0d8992e610c85")})
print("按 _id 查询:", user_by_id)
(2)查询多条文档(find())
返回
Cursor 对象(可迭代,类似生成器,避免内存占用过高),支持链式调用筛选条件。基础查询
# 1. 查询所有文档(无参数)
all_users = collection.find()
for user in all_users: # 迭代 Cursor 对象
print(user)
# 2. 条件查询(如 age > 25 的男性用户)
# MongoDB 条件运算符:$gt(>), $lt(<), $gte(>=), $lte(<=), $ne(!=), $in(包含), $nin(不包含)
male_over_25 = collection.find({"age": {"$gt": 25}, "gender": "male"})
print("25岁以上男性:")
for user in male_over_25:
print(user)
# 3. 只返回指定字段(投影:1 显示,0 隐藏,_id 默认显示,需手动隐藏)
# 示例:只显示 name 和 age,隐藏 _id
users_projection = collection.find(
{"gender": "female"}, # 条件
{"name": 1, "age": 1, "_id": 0} # 投影
)
for user in users_projection:
print(user) # 输出:{'name': 'Alice', 'age': 25}
排序与分页
- 排序:
sort(字段, 排序方向),pymongo.ASCENDING(升序,默认)、pymongo.DESCENDING(降序) - 分页:
skip(跳过条数)(翻页)、limit(返回条数)(限制结果数)
# 1. 按 age 降序排序(年龄大的在前)
sorted_users = collection.find().sort("age", pymongo.DESCENDING)
print("按年龄降序:")
for user in sorted_users:
print(user["name"], user["age"])
# 2. 分页:跳过前1条,返回2条(第2-3条)
paged_users = collection.find().skip(1).limit(2)
print("分页结果(第2-3条):")
for user in paged_users:
print(user["name"])
3. 更新文档(Update)
支持
update_one()(更新第一条匹配文档)、update_many()(更新所有匹配文档)、replace_one()(替换文档,保留 _id)。(1)更新字段(update_one()/update_many())
需使用更新运算符(如
$set 设值、$inc 自增、$push 数组添加元素)。 # 1. 更新单条:将 Alice 的年龄改为 26($set 设值)
update_result1 = collection.update_one(
{"name": "Alice"}, # 条件
{"$set": {"age": 26, "city": "Beijing"}} # 更新内容(新增 city 字段)
)
print("匹配条数:", update_result1.matched_count) # 1
print("修改条数:", update_result1.modified_count) # 1(若值未变则为 0)
# 2. 更新多条:所有男性用户的 age 加 1($inc 自增)
update_result2 = collection.update_many(
{"gender": "male"},
{"$inc": {"age": 1}} # age = age + 1
)
print("匹配男性条数:", update_result2.matched_count)
print("修改男性条数:", update_result2.modified_count)
# 3. 数组更新:给 Bob 的 hobbies 增加 "swimming"($push)
collection.update_one(
{"name": "Bob"},
{"$push": {"hobbies": "swimming"}}
)
(2)替换文档(replace_one())
替换整个文档(除
_id 外),需传入完整的新文档。# 替换 Bob 的文档(保留 _id)
new_bob = {
"name": "Bob",
"age": 32,
"gender": "male",
"hobbies": ["gaming", "coding", "swimming"],
"city": "Shanghai"
}
replace_result = collection.replace_one({"name": "Bob"}, new_bob)
print("替换成功?", replace_result.acknowledged)
4. 删除文档(Delete)
支持
delete_one()(删除第一条匹配文档)、delete_many()(删除所有匹配文档)。 # 1. 删除单条:删除 name = "Charlie" 的文档
delete_result1 = collection.delete_one({"name": "Charlie"})
print("删除条数(单条):", delete_result1.deleted_count) # 1
# 2. 删除多条:删除 age < 26 的文档
delete_result2 = collection.delete_many({"age": {"$lt": 26}})
print("删除条数(多条):", delete_result2.deleted_count)
# 3. 删除集合所有文档(慎用!)
# collection.delete_many({}) # 条件为空,匹配所有文档
五、进阶操作
1. 索引(提升查询效率)
MongoDB 索引类似 MySQL,可大幅提升查询速度,避免全集合扫描。
(1)创建索引
create_index(字段, unique=True/False):创建单字段索引create_index([(字段1, 方向), (字段2, 方向)]):创建复合索引
# 1. 单字段索引:给 name 字段创建普通索引(非唯一)
collection.create_index("name")
# 2. 唯一索引:给 email 字段创建唯一索引(避免重复值)
collection.create_index("email", unique=True)
# 3. 复合索引:按 age 升序、gender 降序创建复合索引
collection.create_index([("age", pymongo.ASCENDING), ("gender", pymongo.DESCENDING)])
(2)查看与删除索引
# 1. 查看集合所有索引
print("所有索引:", collection.index_information())
# 2. 删除指定索引(按索引名或字段)
collection.drop_index("name_1") # 索引名格式:字段_方向(1 升序,-1 降序)
# 或按字段删除:collection.drop_index("email")
# 3. 删除所有索引(保留默认的 _id 索引)
# collection.drop_indexes()
2. 聚合操作(数据统计)
aggregate() 用于复杂数据统计(如分组、求和、平均值),基于聚合管道(Pipeline)实现。示例:按
gender 分组,统计每组人数和平均年龄:pipeline = [
# 阶段1:筛选 age > 25 的文档
{"$match": {"age": {"$gt": 25}}},
# 阶段2:按 gender 分组,统计 count 和 avg_age
{"$group": {
"_id": "$gender", # 分组字段($gender 表示取文档的 gender 字段)
"count": {"$sum": 1}, # 计数(每组人数)
"avg_age": {"$avg": "$age"} # 平均年龄
}},
# 阶段3:按 count 降序排序
{"$sort": {"count": pymongo.DESCENDING}}
]
# 执行聚合
result = list(collection.aggregate(pipeline)) # 转为列表(Cursor 可迭代)
print("聚合结果:", result)
# 输出示例:[{'_id': 'male', 'count': 1, 'avg_age': 32.0}]
常用聚合运算符:
$match(筛选)、$group(分组)、$sum(求和)、$avg(平均)、$sort(排序)、$limit(限制结果)。3. 事务(MongoDB 4.0+)
MongoDB 事务支持多文档原子操作,仅适用于副本集或分片集群(单机不支持)。
示例:转账场景(A 减钱,B 加钱,要么都成功,要么都失败):
# 1. 开启会话
session = client.start_session()
try:
# 2. 开始事务
session.start_transaction()
# 3. 执行事务操作(A 减 100,B 加 100)
collection.update_one({"name": "A"}, {"$inc": {"balance": -100}}, session=session)
collection.update_one({"name": "B"}, {"$inc": {"balance": 100}}, session=session)
# 4. 提交事务
session.commit_transaction()
print("事务提交成功!")
except Exception as e:
# 5. 出错时回滚
session.abort_transaction()
print(f"事务失败,已回滚:{e}")
finally:
# 6. 关闭会话
session.end_session()
4. 批量操作(高效处理大量数据)
BulkWriteOperation 支持批量执行插入、更新、删除,减少网络请求,提升效率。from pymongo import InsertOne, UpdateOne, DeleteOne
# 定义批量操作列表
bulk_operations = [
InsertOne({"name": "David", "age": 22, "gender": "male"}), # 插入
UpdateOne({"name": "Alice"}, {"$set": {"age": 27}}), # 更新
DeleteOne({"name": "Bob"}) # 删除
]
# 执行批量操作
result = collection.bulk_write(bulk_operations)
print("插入条数:", result.inserted_count)
print("更新条数:", result.modified_count)
print("删除条数:", result.deleted_count)
六、常见问题与最佳实践
1. 数据类型对应
MongoDB 与 Python 数据类型对应关系(部分关键类型):
| MongoDB 类型 | Python 类型 | 说明 |
|---|---|---|
| ObjectId | bson.ObjectId | 文档唯一标识,需导入 ObjectId |
| Date | datetime.datetime | 日期时间,需时区一致 |
| Array | list | 数组 |
| Document | dict | 嵌套文档 |
| Int32/Int64 | int | 整数 |
| Double | float | 浮点数 |
2. 异常处理
实际开发中需捕获连接失败、认证错误、唯一索引冲突等异常:
from pymongo.errors import ConnectionFailure, AuthenticationError, DuplicateKeyError
try:
# 连接数据库
client = MongoClient("mongodb://root:123456@localhost:27017/?authSource=admin")
# 验证连接(强制触发连接)
client.admin.command("ping")
print("连接成功!")
# 插入重复唯一索引字段(触发异常)
collection.insert_one({"email": "alice@example.com"})
collection.insert_one({"email": "alice@example.com"}) # 重复,触发 DuplicateKeyError
except ConnectionFailure:
print("连接失败:MongoDB 服务未启动或地址错误!")
except AuthenticationError:
print("认证失败:用户名或密码错误!")
except DuplicateKeyError:
print("唯一索引冲突:该 email 已存在!")
except Exception as e:
print(f"其他错误:{e}")
finally:
client.close() # 关闭连接
3. 连接池配置
pymongo 默认启用连接池(默认大小 100),可通过 maxPoolSize 调整,避免频繁创建连接: client = MongoClient(
"mongodb://localhost:27017/",
maxPoolSize=50, # 连接池最大连接数
connectTimeoutMS=3000, # 连接超时时间(毫秒)
socketTimeoutMS=5000 # 读写超时时间(毫秒)
)
4. 数据验证(Schema)
MongoDB 3.2+ 支持集合级数据验证,确保插入的文档符合指定规则(类似 SQL 的约束):
# 创建集合时指定验证规则(如 age 必须是 0-150 的整数,name 必选)
validation_rule = {
"$jsonSchema": {
"bsonType": "object",
"required": ["name", "age"], # 必选字段
"properties": {
"name": {
"bsonType": "string",
"description": "姓名必须是字符串"
},
"age": {
"bsonType": "int",
"minimum": 0,
"maximum": 150,
"description": "年龄必须是 0-150 的整数"
}
}
}
}
# 创建带验证的集合
db.create_collection("validated_user", validator=validation_rule)
# 测试:插入不符合规则的文档(会报错)
try:
db.validated_user.insert_one({"name": "Eve", "age": 200}) # age 超过 150
except Exception as e:
print(f"数据验证失败:{e}")
七、总结
Python3 操作 MongoDB 的核心流程为:
安装 pymongo → 连接数据库 → 操作集合 → 文档 CRUD → 进阶优化(索引、聚合、事务)。
安装 pymongo → 连接数据库 → 操作集合 → 文档 CRUD → 进阶优化(索引、聚合、事务)。
关键要点:
pymongo.MongoClient是连接入口,支持本地 / 远程 / 认证连接。- 文档用 Python 字典表示,插入时自动转换为 BSON。
- 查询用
find_one()/find(),支持条件、排序、分页;更新需用$set等运算符。 - 索引和聚合是提升 MongoDB 性能的关键,事务确保数据一致性。
- 生产环境需注意异常处理、连接池配置和数据验证。
浙公网安备 33010602011771号