别院牧志知识库 别院牧志知识库
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • Python 面试题
  • 2025 面试记录
  • 2022 面试记录
  • 2021 面试记录
  • 2020 面试记录
  • 2019 面试记录
  • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
首页
  • 基础

    • 全栈之路
    • 😎Awesome资源
  • 进阶

    • Python 工匠系列
    • 高阶知识点
  • 指南教程

    • Socket 编程
    • 异步编程
    • PEP 系列
  • Python 面试题
  • 2025 面试记录
  • 2022 面试记录
  • 2021 面试记录
  • 2020 面试记录
  • 2019 面试记录
  • 数据库索引原理
  • 基金

    • 基金知识
    • 基金经理
  • 细读经典

    • 德隆-三个知道
    • 孔曼子-摊大饼理论
    • 配置者说-躺赢之路
    • 资水-建立自己的投资体系
    • 反脆弱
  • Git 参考手册
  • 提问的智慧
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 工作
  • 规范

  • Linux

  • 数据库

    • MySQL

    • redis

    • MongoDB

      • MongoDB 与 PyMongo 使用指南
        • 一、MongoDB 简介
          • 核心概念和特点
        • 二、在 Python 中使用 PyMongo 操作 MongoDB
          • 基本使用步骤
          • 重要注意事项
          • 总结
    • 数据库操作记录
    • 数据库设计
    • SQLAlchemy 2.0 教程
  • Git

  • 👨‍💻Web

  • 英语

  • Docker

  • 编辑器

  • 网络

  • 前端

  • 存储

  • 备忘录

  • 如何开始你的单元测试
  • 以程序员的视角看中国——西安篇
  • 💻工作
  • 数据库
  • MongoDB
佚名
2025-07-04
目录

MongoDB 与 PyMongo 使用指南

# 一、MongoDB 简介

MongoDB 是一个开源的、面向文档的 NoSQL 数据库。与传统的关系型数据库 (RDBMS) 不同,它不使用表和行,而是使用 JSON-like 格式的文档 (实际上是 BSON,Binary JSON) 来存储数据。

# 核心概念和特点

  1. 文档 (Document):

    • 数据存储的基本单位,类似于 RDBMS 中的一行记录。

    • 采用 BSON 格式 (Binary JSON),是一种二进制表示形式,扩展了 JSON 数据类型(如 Date, BinData, ObjectId 等)。

    • 文档结构是动态的(无固定模式),同一个集合中的文档可以有不同的字段和结构。例如:

      {
        "_id": ObjectId("5f9d9b3d7e4a6e1a2c8b4567"), // MongoDB 自动生成的唯一主键
        "name": "Alice",
        "age": 30,
        "email": "alice@example.com",
        "hobbies": ["reading", "hiking"],
        "address": {
          "city": "New York",
          "zip": "10001"
        }
      }
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
  2. 集合 (Collection):

    • 相当于 RDBMS 中的表。
    • 是一组相关文档的容器。
    • 集合也不需要预定义模式(Schema-less),文档结构可以灵活变化。
  3. 数据库 (Database):

    • 物理容器,包含多个集合。
    • 一个 MongoDB 实例可以承载多个数据库。
  4. 主要特点:

    • 灵活的模式 (Schema-less/Flexible Schema): 数据结构随应用需求动态变化,无需预先严格定义表结构或执行耗时迁移。
    • 高性能: 面向文档的设计、嵌入式数据模型(减少 JOIN 操作)、索引支持、内存映射存储引擎等使其在读写操作上通常具有高性能,尤其适合处理大量数据和高并发场景。
    • 高可扩展性: 原生支持水平扩展(分片 Sharding),通过将数据分布到多个服务器集群上来处理海量数据和负载。
    • 高可用性: 通过副本集 (Replica Set) 提供自动故障转移和数据冗余。副本集是一组维护相同数据集的 MongoDB 实例,提供冗余并提高数据可用性。
    • 丰富的查询语言: 支持强大的查询操作符(等于、范围、逻辑、正则表达式、地理空间等)、投影、排序、分页、聚合管道等。
    • 索引: 支持各种索引(单字段、复合、多键、文本、地理空间、哈希、TTL 等),显著提高查询速度。
    • 聚合框架 (Aggregation Pipeline): 提供强大的数据处理管道,用于数据转换、分组、统计、连接(lookup)等复杂操作。
    • 地理空间支持: 内置对地理空间坐标数据和查询的支持。
  5. 典型使用场景:

    • 内容管理系统 (CMS)
    • 用户配置文件和个性化数据
    • 实时分析和大数据处理
    • 物联网 (IoT) 应用(存储传感器数据)
    • 移动应用后端
    • 日志和事件数据存储
    • 目录和产品数据(尤其是属性变化多的)
    • 任何需要灵活模式、快速迭代或处理非结构化/半结构化数据的应用。

# 二、在 Python 中使用 PyMongo 操作 MongoDB

PyMongo 是 MongoDB 官方提供的 Python 驱动程序,是与 MongoDB 数据库交互的标准库。它提供了直观的 API 来执行 CRUD(创建、读取、更新、删除)操作和管理数据库。

# 基本使用步骤

  1. 安装 PyMongo: 使用 pip 安装:

    pip install pymongo
    
    1
  2. 连接到 MongoDB:

    • 导入 pymongo 库。
    • 使用 MongoClient 类创建到 MongoDB 实例的连接。需要提供连接字符串(URI)。
    • 默认连接到本地 MongoDB 实例 (mongodb://localhost:27017)。
    from pymongo import MongoClient
    
    # 连接到本地默认实例
    client = MongoClient()  # 等同于 MongoClient('localhost', 27017)
    
    # 或者使用连接字符串 (URI)
    # 连接带认证的远程服务器: mongodb://username:password@host:port/database?authSource=admin
    # client = MongoClient('mongodb://user:pass@server-address:27017/')
    
    1
    2
    3
    4
    5
    6
    7
    8
  3. 获取数据库: 通过 client 对象访问数据库。如果数据库不存在,MongoDB 会在第一次插入数据时自动创建它。

    # 获取名为 'mydatabase' 的数据库
    db = client['mydatabase']
    # 或者
    db = client.mydatabase
    
    1
    2
    3
    4
  4. 获取集合: 通过 db 对象访问集合。同样,集合也会在首次插入文档时自动创建。

    # 获取名为 'users' 的集合
    collection = db['users']
    # 或者
    collection = db.users
    
    1
    2
    3
    4
  5. 执行 CRUD 操作:

    • 插入文档 (Create):

      • insert_one(document): 插入单个文档。返回一个 InsertOneResult 对象,包含 inserted_id(新文档的 _id)。
      • insert_many(list_of_documents): 插入多个文档。返回一个 InsertManyResult 对象,包含 inserted_ids(新文档 _id 的列表)。
      # 插入单个文档
      user1 = {"name": "Bob", "age": 25, "email": "bob@example.com"}
      result = collection.insert_one(user1)
      print(result.inserted_id)  # 打印自动生成的 _id
      
      # 插入多个文档
      user2 = {"name": "Charlie", "age": 35, "city": "London"}
      user3 = {"name": "Diana", "occupation": "Engineer", "active": True}
      result = collection.insert_many([user2, user3])
      print(result.inserted_ids)  # 打印所有新 _id 的列表
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
    • 查询文档 (Read):

      • find_one(filter=None, projection=None): 查找并返回第一个匹配过滤条件的文档(或无)。filter 是查询条件字典,projection 指定返回哪些字段(1 包含,0 排除)。
      • find(filter=None, projection=None): 查找并返回一个游标 (Cursor) 对象,该对象可迭代所有匹配文档。同样可以使用 filter 和 projection。
      # 查找单个文档 (按名字)
      user = collection.find_one({"name": "Bob"})
      print(user)  # 输出: {'_id': ObjectId('...'), 'name': 'Bob', 'age': 25, ...}
      
      # 查找所有年龄大于 30 的文档,只返回 name 和 email 字段
      query = {"age": {"$gt": 30}}  # $gt 是 "大于" 操作符
      projection = {"_id": 0, "name": 1, "email": 1}  # 排除 _id, 包含 name 和 email
      cursor = collection.find(query, projection)
      for doc in cursor:
          print(doc)  # 输出类似: {'name': 'Charlie', 'email': 'charlie@example.com'} (假设 Charlie 有 email)
                    # 注意: 上面插入的 Charlie 没有 email 字段,所以这里不会显示 email
      
      # 查询所有文档
      all_users = collection.find()
      for user in all_users:
          print(user)
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
    • 更新文档 (Update):

      • update_one(filter, update, upsert=False): 更新第一个匹配 filter 的文档。update 是描述修改操作的字典(使用 $set, $unset, $inc 等更新操作符)。upsert=True 表示如果没有匹配项则插入新文档。返回 UpdateResult 对象。
      • update_many(filter, update, upsert=False): 更新所有匹配 filter 的文档。
      # 更新 Bob 的年龄 (使用 $set 操作符)
      filter = {"name": "Bob"}
      update = {"$set": {"age": 26, "city": "Paris"}}  # 更新 age 字段,添加/更新 city 字段
      result = collection.update_one(filter, update)
      print(result.modified_count)  # 打印被修改的文档数量 (应该是 1)
      
      # 为所有年龄大于 30 的用户添加一个 'vip' 标志
      filter = {"age": {"$gt": 30}}
      update = {"$set": {"vip": True}}
      result = collection.update_many(filter, update)
      print(result.modified_count)  # 打印被修改的文档数量
      
      # 使用 upsert (如果不存在 "Eve", 则插入新文档)
      filter = {"name": "Eve"}
      update = {"$set": {"age": 28}}
      result = collection.update_one(filter, update, upsert=True)
      print(result.upserted_id)  # 如果插入了新文档,打印其 _id
      
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
    • 删除文档 (Delete):

      • delete_one(filter): 删除第一个匹配 filter 的文档。返回 DeleteResult 对象。
      • delete_many(filter): 删除所有匹配 filter 的文档。
      # 删除名字为 "Charlie" 的文档
      result = collection.delete_one({"name": "Charlie"})
      print(result.deleted_count)  # 打印被删除的文档数量 (应该是 1)
      
      # 删除所有标记为 'inactive' 的文档 (假设有 'status' 字段)
      # result = collection.delete_many({"status": "inactive"})
      # print(result.deleted_count)
      
      1
      2
      3
      4
      5
      6
      7
  6. 索引管理 (可选但重要):

    • 索引可以极大提高查询速度。
    • 使用 create_index(index_spec, options) 方法创建索引。
    • index_spec 是一个元组列表 [(field, direction), ...],direction 为 1(升序)或 -1(降序)。单字段索引可以简写为字符串。
    • 常见选项:unique=True(唯一索引),background=True(后台创建)。
    # 在 'email' 字段上创建唯一索引
    collection.create_index([("email", 1)], unique=True)
    
    # 在 'name' 上创建升序索引
    collection.create_index("name")  # 等同于 [("name", 1)]
    
    # 在 'age' 和 'city' 上创建复合索引 (先按 age 升序, 再按 city 降序)
    collection.create_index([("age", 1), ("city", -1)])
    
    1
    2
    3
    4
    5
    6
    7
    8
  7. 聚合管道 (Aggregation):

    • 使用 aggregate(pipeline) 方法执行复杂的聚合操作。
    • pipeline 是一个由多个聚合阶段(stage)组成的列表。每个阶段是一个字典,描述一个操作($match, $group, $sort, $project, $lookup 等)。
    # 示例:按城市分组,计算每个城市的平均年龄和用户数量
    pipeline = [
        {"$group": {
            "_id": "$city",  # 分组依据字段
            "averageAge": {"$avg": "$age"},  # 计算平均年龄
            "count": {"$sum": 1}  # 计算用户数量
        }},
        {"$sort": {"count": -1}}  # 按用户数量降序排序
    ]
    results = collection.aggregate(pipeline)
    for result in results:
        print(result)  # 输出类似: {'_id': 'Paris', 'averageAge': 26.0, 'count': 1}
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
  8. 关闭连接 (通常由上下文管理): 虽然 Python 的垃圾回收通常会关闭连接,但显式关闭是好的实践。通常使用 with 语句确保连接关闭:

    with MongoClient() as client:
        db = client.mydatabase
        collection = db.users
        # ... 执行操作 ...
    # 离开 with 块后,连接会自动关闭
    
    1
    2
    3
    4
    5

# 重要注意事项

  1. _id 字段: MongoDB 要求每个文档都有一个唯一的 _id 字段作为主键。如果你在插入时没有提供,MongoDB 会自动生成一个 ObjectId。
  2. BSON 类型: PyMongo 会自动在 Python 类型和 BSON 类型之间转换(如 datetime.datetime <-> BSON Date, bytes <-> BSON Binary)。特别注意 ObjectId 类型(from bson import ObjectId)。
  3. 错误处理: 数据库操作可能失败(网络问题、唯一键冲突、权限问题等)。务必使用 try-except 块捕获 pymongo.errors 模块中的异常(如 DuplicateKeyError, ConnectionFailure, OperationFailure)。
  4. 连接池: MongoClient 默认管理一个连接池以提高效率。避免为每个操作创建新客户端。
  5. 投影 (projection): 只查询需要的字段可以节省网络传输和内存开销。
  6. 批量操作: 对于大量插入、更新或删除,优先使用 insert_many, update_many, delete_many 或 bulk_write 代替循环调用单文档操作,性能更高。
  7. 安全性:
    • 生产环境务必启用身份验证 (authSource)。
    • 使用 TLS/SSL 加密连接。
    • 遵循最小权限原则配置数据库用户权限。

# 总结

MongoDB 提供了灵活、高性能、可扩展的 NoSQL 数据存储方案。PyMongo 是 Python 开发者与 MongoDB 交互的强大工具,其 API 设计直观,覆盖了数据库操作的方方面面,从基本的 CRUD 到索引管理、聚合管道等高级功能。理解 MongoDB 的文档模型和 PyMongo 的基本用法,是构建现代 Python 应用后端的重要技能。

编辑 (opens new window)
#MongoDB#数据库
上次更新: 2025-07-04, 09:03:19
深入了解 Redis 底层数据结构
数据库操作记录

← 深入了解 Redis 底层数据结构 数据库操作记录→

最近更新
01
FastAPI 依赖注入:从入门到实践
07-04
02
FastAPI 快速上手指南
07-04
03
本事与投资
06-20
更多文章>
Theme by Vdoing | Copyright © 2019-2025 IMOYAO | 别院牧志
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式