MongoDB 入门

  • MongoDB 是一种流行的 NoSQL 数据库系统,它使用了灵活的文档导向的模型来存储和管理数据。与传统的关系数据库管理系统(RDBMS)不同,MongoDB 不需要固定的表结构,它允许数据记录在没有预先定义模式的情况下被存储。这意味着数据库的记录可以有不同的字段,这对于处理大量异构数据非常有用。
  • MongoDB 的数据结构类似于 JSON 对象,其格式称为 BSON(Binary JSON),这种格式支持更丰富的数据类型。MongoDB 提供了强大的查询语言,支持复杂的查询、索引、聚合操作等。它还具有高可扩展性,可以通过分片等技术实现水平扩展,支持大规模的数据存储和处理。
  • MongoDB 最初是用 C++ 语言编写的。C++ 以其性能优势和系统级编程能力被广泛用于开发数据库系统,这使得 MongoDB 可以高效地处理数据操作和内存管理。尽管 MongoDB 的核心是用 C++ 编写的,但它也支持多种语言的驱动,例如 Python、Java、Node.js 等,开发者可以使用这些驱动在不同的应用程序中与 MongoDB 交互。
  • MongoDB 文档

核心特点

  1. 文档导向
    • MongoDB 是基于文档的,这意味着它管理的基本数据单元是文档,这些文档类似于 JSON 对象,使得数据的读写非常直观。
    • 文档可以嵌套复杂的数据类型,如数组和文档。
  2. 动态模式
    • 数据可以在没有固定结构的情况下被存储,这给应对不断变化的数据结构带来了极大的灵活性。
  3. 可扩展性
    • MongoDB 支持水平扩展,通过分片可以分布数据到多个服务器。
    • 复制集确保数据的高可用性和冗余。
  4. 强大的查询语言
    • 它支持丰富的查询操作,包括文档和字段级别的查询,以及正则表达式等。
  5. 索引优化
    • 支持多种类型的索引,以优化查询速度,包括地理空间索引、全文索引等。
  6. 聚合管道
    • MongoDB 的聚合框架提供了一个功能丰富的数据处理管道,允许数据在多个阶段进行处理和转换。
  7. 格外的驱动支持
    • 有多种编程语言的官方支持,如 Python、Java、C#、Node.js、Ruby 等。
  8. 存储过程
    • 支持 JavaScript 编写的服务器端函数。
  9. 灵活的部署
    • MongoDB 可以在多种环境中运行,包括云平台服务。
  10. 丰富的资源
    • MongoDB 社区非常活跃,提供大量的资源和支持,从而简化了开发和维护的工作。
  11. 强大的交易支持
    • 尽管是 NoSQL 数据库,MongoDB 也支持多文档事务,类似于关系型数据库的 ACID 事务。
  1. 访问 MongoDB 的官方下载中心。
  2. 选择 "Windows" 作为操作系统,选择所需版本,然后点击 "下载"。
  3. 运行下载的 .msi 安装程序,并跟随提示进行安装。
  4. 完成安装后,可以将 MongoDB 的安装目录添加到系统的 PATH 环境变量中,以便在任何命令行窗口中运行 MongoDB。
  5. 你还需要手动创建一个数据库存储目录(默认是 C:\data\db)。
  6. 启动 MongoDB 服务。在命令行中运行 mongod
  7. 要开始使用 MongoDB,你可以在另一个命令行窗口中运行 mongo 来启动 MongoDB Shell。
  1. 对于 macOS,可以使用 Homebrew 来安装 MongoDB。如果还没有安装 Homebrew,请先安装它。
  2. 打开终端。
  3. 运行 brew tap mongodb/brew 来添加 MongoDB 的官方 Homebrew tap。
  4. 然后运行 brew install mongodb-community@7.0 来安装最新版本的 MongoDB。
  5. 通过 brew services start mongodb-community@7.0 命令启动 MongoDB 服务。
  6. 使用 mongo 命令来连接 MongoDB 服务并打开 MongoDB Shell。

对于 Linux,安装步骤将因发行版本不同而有所变化。以下是基于 Ubuntu 的安装步骤:

  1. 导入 MongoDB 公钥。这样可以确保 deb 软件包的一致性和真实性。
    1
    2
    3
    curl -fsSL https://pgp.mongodb.com/server-7.0.asc | \
    sudo gpg -o /usr/share/keyrings/mongodb-server-7.0.gpg \
    --dearmor
  2. 创建列表文件
    1
    echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-7.0.gpg ] https://repo.mongodb.com/apt/ubuntu jammy/mongodb-org/7.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-7.0.list
  3. 重新加载本地包数据库
    1
    sudo apt-get update
  4. 安装 MongoDB
    1
    sudo apt-get install -y mongodb-org
  5. 启动 MongoDB 服务
    1
    sudo systemctl start mongod
  6. 如果你想 MongoDB 随系统启动而自动运行,使用
    1
    sudo systemctl enable mongod
  7. 连接到 MongoDB
    1
    mongo

MySQL 与 MongoDB 对比

MySQL MongoDB
database db(数据库)
table collection(集合)
一条数据 document(文档)

MongoDB 之 db 操作

  • 创建数据库

    MongoDB 中并不需要显式创建数据库。当你首次向数据库中的集合(collection)插入一条文档(document)时,MongoDB 会自动创建这个数据库。

    1
    2
    use myNewDatabase             // 切换到名为myNewDatabase的数据库,如果不存在,则准备创建
    db.myNewCollection.insertOne({a: 1}) // 向名为myNewCollection的集合插入一个文档,这将自动创建数据库和集合
  • 选择数据库

    使用 use 命令加上数据库名来选择数据库。

    1
    use myDatabase  // 切换到名为myDatabase的数据库
  • 查看当前数据库

    要查看当前选定的数据库,你可以使用 db 命令。

    1
    db  // 显示当前数据库
  • 列出所有数据库

    使用 show dbs 命令列出服务器上的所有数据库。

    1
    show dbs  // 列出所有可用的数据库
  • 删除数据库

    要删除当前选中的数据库,可以使用 db.dropDatabase() 命令。

    1
    2
    use myOldDatabase  // 首先切换到你想要删除的数据库
    db.dropDatabase() // 删除当前选中的数据库
  • 其他数据库级别的操作

    • 查看数据库状态db.stats()
    • 创建用户db.createUser()
    • 查看数据库中的集合show collections
    • 备份数据库:使用 mongodump 工具
    • 恢复数据库:使用 mongorestore 工具

MongoDB 之 collection 操作

  • 查看所有集合

    要查看当前数据库中的所有集合,可以使用 show collections 命令。

    1
    show collections

    在 MongoDB 中,运行此命令会列出当前选定数据库中的所有集合的名称。

  • 创建集合

    虽然 MongoDB 会在你第一次向集合插入文档时自动创建集合,但如果你需要创建一个具有特定选项(例如固定大小或索引)的集合,可以使用 db.createCollection() 方法来显式创建它。

    1
    db.createCollection("myNewCollection")

    你还可以传递一个选项对象来指定其它属性,例如设置集合为固定大小。

    1
    db.createCollection("myCappedCollection", { capped: true, size: 100000 })

    在这个例子中,myCappedCollection 是一个固定大小的集合,其大小上限是 100,000 字节。

  • 删除集合

    • 使用 db.collection.drop() 方法来删除一个集合。
      1
      db.myOldCollection.drop()
    • 这条命令将会删除名为 myOldCollection 的集合。如果操作成功,它将返回 true;如果你尝试删除一个不存在的集合,它将返回 false
    • 注意:删除集合是不可逆的,并且会同时删除集合中的所有文档。

MongoDB 之 document 操作

  • 插入文档

    • 插入单个文档

      使用 insertOne 方法来插入一个文档到指定的集合中。如果集合不存在,MongoDB 会自动创建这个集合。

      1
      2
      3
      4
      5
      db.collectionName.insertOne({
      name: "John Doe",
      age: 30,
      email: "johndoe@example.com"
      })

      这个命令会在 collectionName 集合中插入一个包含 nameageemail 字段的文档。

    • 插入多个文档

      使用 insertMany 方法插入多个文档到集合中。这个方法接收一个文档数组作为参数。

      1
      2
      3
      4
      db.collectionName.insertMany([
      { name: "Jane Doe", age: 25, email: "janedoe@example.com" },
      { name: "Jim Beam", age: 35, email: "jimbeam@example.com" }
      ])

      这个命令会在 collectionName 集合中插入两个文档。

    • 附加说明

      • 在 MongoDB 中,每个插入的文档都会自动赋予一个 _id 字段,这是文档的唯一标识符。如果在插入文档时没有提供 _id 字段,MongoDB 会自动生成一个 ObjectId 类型的 _id 字段。
      • 插入文档后,MongoDB 会返回一个结果对象,其中包含关于操作的信息,比如影响的文档数和文档的 _id 等。
      • 例如,插入单个文档后的返回结果可能类似这样:
        1
        2
        3
        4
        {
        "acknowledged" : true,
        "insertedId" : ObjectId("5f50c31e1c4ae8635237f460")
        }
      • 同样,使用 insertMany 插入多个文档时,你会得到每个被插入文档的 _id 的列表。
      • 请注意,文档的字段可以是各种数据类型,不仅限于字符串或数字,还可以是数组、另一个文档或者甚至是二进制数据等。
  • 查询文档

    • 查询所有文档

      使用 find() 方法不带任何参数就可以查询集合中的所有文档。

      1
      db.collectionName.find()

      这会显示 collectionName 集合中的所有文档。

    • 查询特定文档

      添加查询条件作为 find() 方法的参数,可以查询满足特定条件的文档。

      1
      db.collectionName.find({ age: { $gt: 25 } })

      这个命令会查询 collectionName 集合中 age 大于 25 的所有文档。

    • 查询并返回特定字段

      如果你只需要文档中的特定字段,可以在 find() 方法中指定第二个参数来包含或排除字段。

      1
      db.collectionName.find({}, { name: 1, age: 1, _id: 0 })

      这个命令会返回 collectionName 集合中所有文档的 nameage 字段,并排除 _id 字段。

    • 查询单个文档

      使用 findOne() 方法可以返回满足查询条件的第一个文档。

      1
      db.collectionName.findOne({ name: "John Doe" })

      这个命令会查询 collectionName 集合中第一个名字为 "John Doe" 的文档。

    • 使用查询操作符

      查询操作符可以提供更强大的查询功能,如范围查询、正则表达式查询等。

      1
      db.collectionName.find({ age: { $lte: 30 } })

      这个命令会查询 collectionName 集合中 age 小于或等于 30 的所有文档。

    • 多条件查询

      • $and

        $and 操作符可以连接多个查询条件,只有同时满足所有条件的文档才会被查询到

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 查询年龄大于等于20且名字为"John"的文档
        results = collection.find({
        "$and": [
        {"age": {"$gte": 20}},
        {"name": "John"}
        ]
        })

        for document in results:
        print(document)

      • $or

        $or 操作符至少满足其中一个条件的文档都会被查询到

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 查询名字为"John"或年龄小于30的文档
        results = collection.find({
        "$or": [
        {"name": "John"},
        {"age": {"$lt": 30}}
        ]
        })

        for document in results:
        print(document)

      • $nor

        $nor 操作符用来查询不满足任何条件的文档

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        # 查询年龄不大于20且名字不为"John"的文档
        results = collection.find({
        "$nor": [
        {"age": {"$gt": 20}},
        {"name": "John"}
        ]
        })

        for document in results:
        print(document)

      • $not

        $not 操作符用来查询不满足指定条件的文档

        1
        2
        3
        4
        5
        6
        7
        8
        # 查询名字不以字母"J"开头的文档
        results = collection.find({
        "name": {"$not": {"$regex": "^J"}}
        })

        for document in results:
        print(document)

      • 组合 $and$or

        你也可以在同一个查询中组合使用 $and$or

        1
        2
        3
        4
        5
        6
        7
        8
        9
        10
        11
        12
        13
        14
        15
        16
        # 查询年龄大于20且名字为"John"或者年龄小于30的文档(注意优先级和分组)
        results = collection.find({
        "$and": [
        {
        "$or": [
        {"name": "John"},
        {"age": {"$lt": 30}}
        ]
        },
        {"age": {"$gt": 20}}
        ]
        })

        for document in results:
        print(document)

    • 排序查询结果

      使用 sort() 方法对查询结果进行排序。

      1
      db.collectionName.find().sort({ age: -1 })

      这个命令会返回 collectionName 集合中的所有文档,结果按 age 字段降序排序。

    • 限制查询结果数量

      使用 limit() 方法限制查询结果的数量。

      1
      db.collectionName.find().limit(5)

      这个命令会返回 collectionName 集合中的前 5 个文档。

    • 跳过指定数量的文档

      使用 skip() 方法跳过查询结果中的指定数量的文档。

      1
      db.collectionName.find().skip(5)

      这个命令会跳过 collectionName 集合中的前 5 个文档,并返回之后的文档。

    • 链式使用查询方法

      find() 方法返回的是一个游标,你可以链式调用 sort()limit()skip() 方法。

      1
      db.collectionName.find().sort({ age: 1 }).limit(5).skip(10)

      这个命令会查询 collectionName 集合,跳过前 10 个文档,然后按 age 升序排序,并且只返回接下来的 5 个文档。

  • 更新文档

    • 更新单个文档

      使用 updateOne 方法可以更新满足条件的第一个文档。你需要提供一个查询条件和要更新的字段。

      1
      2
      3
      4
      db.collectionName.updateOne(
      { name: "John Doe" },
      { $set: { email: "john.doe@newdomain.com" } }
      )

      这个命令会在 collectionName 集合中查找第一个名为 "John Doe" 的文档,并更新其 email 字段。

    • 更新多个文档

      使用 updateMany 方法可以更新所有满足条件的文档。

      1
      2
      3
      4
      db.collectionName.updateMany(
      { age: { $gt: 30 } },
      { $set: { status: "senior" } }
      )

      这个命令会更新 collectionName 集合中所有 age 大于 30 的文档,为他们添加或更新 status 字段为 "senior"。

    • 替换文档

      使用 replaceOne 方法可以替换满足条件的第一个文档。

      1
      2
      3
      4
      db.collectionName.replaceOne(
      { name: "John Doe" },
      { name: "John Doe", age: 50, status: "senior" }
      )

      这个命令会在 collectionName 集合中查找第一个名为 "John Doe" 的文档,并完全替换它(除了 _id 字段,除非你显式地也替换了它)。

    • 原子操作符

      MongoDB 提供一系列原子操作符来更新文档,如 $set 用于设置字段值,$inc 用于增加字段值,$push 用于数组字段添加元素等。

      1
      2
      3
      4
      db.collectionName.updateOne(
      { name: "Jane Doe" },
      { $inc: { age: 1 } }
      )

      这个命令会将 collectionName 集合中名为 "Jane Doe" 的文档的 age 字段增加 1。

    • 更新文档的选项

      updateOneupdateMany 方法还接受额外的选项参数。例如,如果你想在没有匹配文档时插入一个新文档,可以使用 upsert 选项。

      1
      2
      3
      4
      5
      db.collectionName.updateOne(
      { name: "New User" },
      { $set: { age: 30, status: "new" } },
      { upsert: true }
      )

      如果找不到名为 "New User" 的文档,上面的命令将插入一个新文档。

    • 注意事项

      • 更新操作默认只作用于第一个匹配的文档updateOnereplaceOne);如果你需要更新多个文档,则应使用 updateMany
      • 更新操作不会修改文档的 _id 值。
      • 如果更新命令导致文档字段的减少,那么这些字段将被删除。
      • 使用 updateMany 时要特别小心,因为它会更新所有匹配的文档。
  • 删除文档

    • 删除单个文档

      使用 deleteOne 方法删除满足条件的第一个文档。

      1
      db.collectionName.deleteOne({ name: "John Doe" })

      这个命令会在 collectionName 集合中删除第一个名字为 "John Doe" 的文档。

    • 删除多个文档

      使用 deleteMany 方法删除所有满足条件的文档。

      1
      db.collectionName.deleteMany({ status: "inactive" })

      这个命令会删除 collectionName 集合中所有 status 字段为 "inactive" 的文档。

    • 删除所有文档

      要删除集合中的所有文档,可以传递一个空的查询对象给 deleteMany 方法。

      1
      db.collectionName.deleteMany({})

      这会删除 collectionName 集合中的所有文档。请注意,这不会删除集合本身。

    • 注意事项

      • 在执行删除操作之前,请确保你有充分的备份,以防止数据丢失。
      • 考虑到安全性,MongoDB 不允许无条件删除集合中的所有文档;必须提供一个空的查询对象 {} 以指明你确实打算删除所有文档。
      • 删除操作是不可逆的,一旦执行,被删除的文档将无法恢复。
      • 对于大规模的删除操作,可能需要考虑对性能的影响,以及是否要在非高峰时段执行。
  • 计数文档

    • 使用 countDocuments()

      这个方法提供了一个准确的文档数量,基于查询过滤器。

      1
      db.collectionName.countDocuments({ status: "active" })

      以上命令会返回 collectionName 集合中状态为 "active" 的文档数量。

    • 使用 estimatedDocumentCount()

      这个方法提供了一个估算值,这通常更快,但不会考虑任何查询过滤器。

      1
      db.collectionName.estimatedDocumentCount()

      以上命令会返回 collectionName 集合中的估算文档数量。

    • 注意事项

      • countDocuments() 实际上会执行一个查询,并且对结果进行计数,因此如果集合很大且有复杂的查询条件,这可能会比较慢。
      • estimatedDocumentCount() 方法基于集合的元数据迅速返回一个估算值,这个数字可能不会包括最近的集合更改,如果最近没有发生写入操作,那么这个方法返回结果非常快,适用于较大的数据集。
      • countDocuments()estimatedDocumentCount() 在返回结果时的性能差异通常在于是否使用索引和集合的大小。
  • 排序文档

    • 排序单个字段

      例如,如果你想要按照名字升序排序:

      1
      db.collectionName.find().sort({ name: 1 })

      如果你想要按照名字降序排序:

      1
      db.collectionName.find().sort({ name: -1 })
    • 排序多个字段

      如果你想要按照多个字段进行排序,比如先按照年龄升序排序,如果年龄相同再按照名字升序排序:

      1
      db.collectionName.find().sort({ age: 1, name: 1 })
    • 使用索引进行排序

      为了提高排序操作的效率,尤其是在处理大数据集时,你应该考虑使用索引。如果排序的字段上有索引,MongoDB 将能够更高效地进行排序操作。

    • 注意事项

      • 对于大量数据的排序操作,如果没有合适的索引,排序可能非常耗时。
      • 在没有索引支持的情况下,MongoDB 将所有文档加载到内存中进行排序。如果处理的数据量超过了系统的可用内存,这将导致性能问题。
      • 如果排序操作耗尽了 MongoDB 的排序操作内存限制(默认是 32MB),查询将会失败。你可以通过创建索引或增加内存限制来解决这个问题。
  • 限制查询结果

    • 限制查询结果

      例如,如果你只想获取 5 个文档,你可以这样做:

      1
      db.collectionName.find().limit(5)

      这个命令会返回 collectionName 集合中的前 5 个文档。

    • 结合排序和限制

      你还可以结合使用排序和限制,比如,如果你想获取分数最高的 5 个学生:

      1
      db.collectionName.find().sort({ score: -1 }).limit(5)

      这将会按分数降序排序后,返回前 5 个文档。

    • 结合跳过和限制以进行分页

      如果你想实现分页效果,你可以结合使用 skip()limit() 方法。例如,如果每页显示 5 个文档,并且你想获取第二页的文档:

      1
      db.collectionName.find().skip(5).limit(5)

      这里,skip(5) 会跳过前 5 个文档,即第一页的内容,而 limit(5) 则限制了只返回 5 个文档,即第二页的内容。

    • 注意事项

      • 使用 limit() 方法可以避免发送太多的数据给客户端,这对于性能和带宽都是一个好处。
      • sort() , skip() , 和 limit() 方法的组合通常用于实现分页功能,但请注意 skip() 操作在大数据集合中可能会导致性能问题,因为它仍然需要遍历所有被跳过的文档。
      • 对于更高效的分页,特别是在处理大量数据时,可以考虑使用范围查询(range queries)来代替 skip()

PyMongo 之 document 操作

  • 插入文档

    • 插入单个文档

      要插入单个文档到 MongoDB 集合中,可以使用 insert_one() 方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # 定义要插入的单个文档
      my_document = {
      "name": "John Doe",
      "age": 30,
      "address": "123 Elm Street"
      }

      # 执行插入操作
      insert_result = collection.insert_one(my_document)

      # 打印插入文档的ID
      print(f"Inserted document with id: {insert_result.inserted_id}")

    • 插入多个文档

      如果你想一次性插入多个文档,可以使用 insert_many() 方法。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      # 定义要插入的多个文档
      my_documents = [
      {"name": "Jane Doe", "age": 25, "address": "456 Maple Street"},
      {"name": "Alice Johnson", "age": 28, "address": "789 Oak Street"},
      {"name": "Bob Smith", "age": 32, "address": "101 Pine Street"}
      ]

      # 执行插入操作
      insert_result = collection.insert_many(my_documents)

      # 打印插入文档的ID列表
      print(f"Inserted documents with ids: {insert_result.inserted_ids}")

    • 说明

      • 当使用 insert_one()insert_many() 方法时,PyMongo 会自动在每个文档中添加一个 _id 字段,用作该文档的唯一标识。如果文档中已经包含了 _id 字段,则 PyMongo 将使用该值作为文档的标识。
      • 在执行插入操作后,insert_one()insert_many() 方法都会返回一个结果对象,该对象包含了插入操作的信息,例如 inserted_idinserted_ids 属性,它们分别代表插入的单个文档的 ID 或多个文档的 ID 列表。
  • 查询文档

    • 查询单个文档

      使用 find_one() 方法来查询单个文档。如果有多个文档匹配查询条件,find_one() 将返回第一个匹配的文档。

      1
      2
      3
      # 查询名字为"John Doe"的第一个文档
      document = collection.find_one({'name': 'John Doe'})
      print(document)
    • 查询多个文档

      使用 find() 方法来查询多个文档。find() 返回一个可迭代的游标对象,可以遍历集合中所有匹配的文档。

      1
      2
      3
      4
      5
      6
      7
      # 查询所有文档
      for doc in collection.find():
      print(doc)

      # 查询所有名字为"John Doe"的文档
      for doc in collection.find({'name': 'John Doe'}):
      print(doc)
    • 使用查询操作符

      MongoDB 提供了多种查询操作符,例如 $lt (小于), $gt (大于), $eq (等于), 等等,来精细化查询条件。

      1
      2
      3
      # 查询年龄大于25的所有文档
      for doc in collection.find({'age': {'$gt': 25}}):
      print(doc)
    • 限制查询结果数目

      你可以结合使用 limit() 方法来限制查询结果的数目。

      1
      2
      3
      # 查询年龄大于25,但仅返回前两个文档
      for doc in collection.find({'age': {'$gt': 25}}).limit(2):
      print(doc)
    • 指定返回的字段

      使用 projection 参数来指定返回的字段。

      1
      2
      3
      # 只返回name和age字段
      for doc in collection.find({}, {'name': 1, 'age': 1, '_id': 0}):
      print(doc)

      在这里,1 表示包含字段,0 表示排除字段。_id 字段默认是包含的,除非明确排除。

    • 排序查询结果

      可以使用 sort() 方法对查询结果进行排序。

      1
      2
      3
      4
      5
      6
      7
      # 按年龄升序排序
      for doc in collection.find().sort('age', pymongo.ASCENDING):
      print(doc)

      # 按年龄降序排序
      for doc in collection.find().sort('age', pymongo.DESCENDING):
      print(doc)
    • find_one_and_delete

      这个方法查找并删除一个文档。它返回被删除的文档。

      1
      2
      3
      4
      5
      # 查找并删除名字为"John Doe"的第一个文档
      deleted_document = collection.find_one_and_delete({'name': 'John Doe'})

      # 输出被删除的文档
      print(deleted_document)
    • find_one_and_replace

      这个方法查找一个文档并用另一个文档替换它。它返回原始文档,或者如果设置了 return_document 参数,则返回更新后的文档。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # 查找名字为"John Doe"的第一个文档,并用新的文档替换它
      new_document = {'name': 'John Doe', 'age': 30, 'address': '123 Park Ave'}
      replaced_document = collection.find_one_and_replace(
      {'name': 'John Doe'},
      new_document,
      return_document=pymongo.ReturnDocument.AFTER
      )

      # 输出替换后的文档
      print(replaced_document)
    • find_one_and_update

      这个方法查找一个文档并更新它。可以指定更新的具体操作,比如使用 $set 来修改字段。它返回原始文档,或者如果设置了 return_document 参数,则返回更新后的文档。

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      # 查找名字为"John Doe"的第一个文档,并更新它的年龄
      updated_document = collection.find_one_and_update(
      {'name': 'John Doe'},
      {'$set': {'age': 29}},
      return_document=pymongo.ReturnDocument.AFTER
      )

      # 输出更新后的文档
      print(updated_document)

  • 更新文档

    • 更新单个文档

      使用 update_one() 方法来更新单个文档。你需要提供一个查询条件(用于找到需要更新的文档)和一个更新操作符(如 $set 用于指定更新的字段和值)。

      1
      2
      3
      4
      5
      # 更新名字为"John Doe"的第一个匹配文档的年龄
      result = collection.update_one({'name': 'John Doe'}, {'$set': {'age': 29}})

      # 输出被更新文档的数量
      print(f"Documents updated: {result.modified_count}")
    • 更新多个文档

      使用 update_many() 方法来更新多个文档。和 update_one() 使用相同的查询条件和更新操作符,但会更新所有匹配的文档。

      1
      2
      3
      4
      5
      # 更新所有名字为"John Doe"的文档的地址
      result = collection.update_many({'name': 'John Doe'}, {'$set': {'address': '123 Main Street'}})

      # 输出被更新文档的数量
      print(f"Documents updated: {result.modified_count}")
    • 原子操作符

      除了 $set 之外,还可以使用其他的原子操作符,比如 $inc 用于增加数值字段,或 $push 用于向数组字段添加元素。

      1
      2
      3
      4
      5
      6
      7
      # 将名为"John Doe"的文档的"visit_count"字段增加1
      result = collection.update_one({'name': 'John Doe'}, {'$inc': {'visit_count': 1}})
      print(f"Documents updated: {result.modified_count}")

      # 向名为"John Doe"的文档的"tags"数组添加一个新元素
      result = collection.update_one({'name': 'John Doe'}, {'$push': {'tags': 'new-tag'}})
      print(f"Documents updated: {result.modified_count}")
    • upsert 操作

      如果你想在更新操作中进行 "upsert"(如果文档不存在则插入),你可以设置 upsert=True

      1
      2
      3
      4
      5
      # 如果找不到则插入新文档
      result = collection.update_one({'name': 'Eve Adams'}, {'$set': {'age': 30}}, upsert=True)
      print(f"Documents matched: {result.matched_count}")
      print(f"Documents modified: {result.modified_count}")
      print(f"Upserted ID: {result.upserted_id}")

      如果查询条件没有匹配任何文档,并且 upsert=True,则 MongoDB 将插入一个包含查询条件和更新操作指定字段的新文档。

  • 删除文档

    • 删除单个文档

      使用 delete_one() 方法可以删除一个与查询条件匹配的文档。如果有多个文档匹配,只有第一个会被删除。

      1
      2
      3
      4
      5
      # 删除名字为"John Doe"的第一个匹配文档
      delete_result = collection.delete_one({'name': 'John Doe'})

      # 输出被删除文档的数量
      print(f"Documents deleted: {delete_result.deleted_count}")
    • 删除多个文档

      使用 delete_many() 方法可以删除所有匹配查询条件的文档。

      1
      2
      3
      4
      5
      # 删除所有名字为"John Doe"的文档
      delete_result = collection.delete_many({'name': 'John Doe'})

      # 输出被删除文档的数量
      print(f"Documents deleted: {delete_result.deleted_count}")
    • 删除所有文档

      如果你想删除集合中的所有文档,可以传递一个空的查询对象给 delete_many() 方法。

      1
      2
      3
      4
      5
      # 警告:这将删除集合中的所有文档
      delete_result = collection.delete_many({})

      # 输出被删除文档的数量
      print(f"All documents deleted: {delete_result.deleted_count}")

      请注意,在执行删除操作时要特别小心,因为这些操作是不可逆的。对于生产环境中的数据,通常建议先执行查询确认需要删除的文档,然后再进行删除操作。同时,定期备份数据库是一种好的习惯,以防止数据丢失。

  • 排序文档

    • 基本排序

      你可以使用 sort() 方法来定义排序的字段和方向。使用 pymongo.ASCENDING 作为升序,pymongo.DESCENDING 作为降序。

      1
      2
      3
      4
      5
      6
      7
      8
      # 升序排序
      documents = collection.find().sort('fieldname', pymongo.ASCENDING)

      # 降序排序
      documents = collection.find().sort('fieldname', pymongo.DESCENDING)

      for document in documents:
      print(document)
    • 多字段排序

      如果你想根据多个字段进行排序,可以向 sort() 方法传递一个包含多个元组的列表,每个元组包含字段名称和方向。

      1
      2
      3
      4
      5
      6
      7
      8
      # 根据多个字段进行排序,例如先按 age 升序,然后按 name 降序
      documents = collection.find().sort([
      ('age', pymongo.ASCENDING),
      ('name', pymongo.DESCENDING)
      ])

      for document in documents:
      print(document)
    • 使用链式调用进行排序

      在 PyMongo 中,可以通过对查询结果进行链式调用来进行多步骤的数据处理,包括排序。

      1
      2
      3
      4
      5
      # 链式调用:先筛选年龄大于25的文档,然后按年龄升序排序
      documents = collection.find({'age': {'$gt': 25}}).sort('age', pymongo.ASCENDING)

      for document in documents:
      print(document)
  • 计数文档

    在 PyMongo 中,你可以使用 count_documents() 方法来准确地统计满足特定查询条件的文档数量。如果你只需要一个大致的估计值,也可以使用 estimated_document_count() 方法,它基于集合的元数据信息快速给出一个近似的文档数量。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    from pymongo import MongoClient

    # 连接到MongoDB
    client = MongoClient('mongodb://localhost:27017/')

    # 选择数据库和集合
    db = client['your_database']
    collection = db['your_collection']

    # 使用count_documents来计数满足条件的文档数量
    # 例如,计数年龄大于20的文档
    count = collection.count_documents({'age': {'$gt': 20}})
    print("Number of documents where age is greater than 20:", count)

    # 如果你想计数集合中所有的文档,可以传递一个空的查询对象
    total_count = collection.count_documents({})
    print("Total number of documents in the collection:", total_count)

    # 使用estimated_document_count来快速估计集合中的文档总数
    # 注意这不会应用任何过滤条件,并且可能不是完全准确的
    estimated_count = collection.estimated_document_count()
    print("Estimated total number of documents in the collection:", estimated_count)

查询条件操作符

操作符 描述 示例
$eq 等于(equal to) {'age': {'$eq': 30}} 匹配年龄等于 30 的文档
$gt 大于(greater than) {'age': {'$gt': 30}} 匹配年龄大于 30 的文档
$gte 大于等于(greater than or equal to) {'age': {'$gte': 30}} 匹配年龄大于等于 30 的文档
$lt 小于(less than) {'age': {'$lt': 30}} 匹配年龄小于 30 的文档
$lte 小于等于(less than or equal to) {'age': {'$lte': 30}} 匹配年龄小于等于 30 的文档
$ne 不等于(not equal to) {'age': {'$ne': 30}} 匹配年龄不等于 30 的文档
$in 在给定数组里(in) {'age': {'$in': [25, 30, 35]}} 匹配年龄为 25, 30 或 35 的文档
$nin 不在给定数组里(not in) {'age': {'$nin': [25, 30, 35]}} 匹配年龄不为 25, 30 或 35 的文档
$or 或条件(logical OR) {'$or': [{'age': 20}, {'name': 'John'}]} 匹配年龄为 20 或名字为 John 的文档
$and 与条件(logical AND) {'$and': [{'age': {'$gt': 20}}, {'name': 'John'}]} 匹配年龄大于 20 并且名字为 John 的文档
$not 非条件(logical NOT) {'age': {'$not': {'$lt': 30}}} 匹配年龄不小于 30 的文档
$exists 字段是否存在 {'name': {'$exists': True}} 匹配包含 name 字段的文档
$regex 正则表达式 {'name': {'$regex': '^J'}} 匹配名字以 "J" 开头的文档
$type 类型检查 {'age': {'$type': 'int'}} 匹配年龄字段类型为 integer 的文档
  • 安装 PyMongo

    1
    pip install pymongo
  • 连接到 MongoDB

    1
    2
    3
    4
    from pymongo import MongoClient

    # 创建MongoDB客户端连接对象
    client = MongoClient('mongodb://localhost:27017/')

    如果 MongoDB 运行在不同的主机或端口上,你需要相应地调整连接字符串。

  • 选择数据库和集合

    连接到指定的数据库和集合:

    1
    2
    3
    4
    5
    # 选择数据库
    db = client['my_database']

    # 选择集合
    collection = db['my_collection']

    确保将 'my_database''my_collection' 替换为实际的数据库和集合名称。

  • 插入文档

    插入一个或多个文档到集合中:

    1
    2
    3
    4
    5
    6
    7
    8
    # 插入单个文档
    result = collection.insert_one({'name': 'Alice', 'age': 30})

    # 插入多个文档
    results = collection.insert_many([
    {'name': 'Bob', 'age': 25},
    {'name': 'Charlie', 'age': 35}
    ])
  • 查询文档

    查询集合中的文档:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    # 查询单个文档
    user = collection.find_one({'name': 'Alice'})

    # 查询所有匹配的文档
    users = collection.find({'age': {'$gt': 25}})

    for user in users:
    print(user)

    其中 '$gt' 是一个查询操作符,意味着 “大于”。

  • 更新文档

    更新集合中的一个或多个文档:

    1
    2
    3
    4
    5
    # 更新单个文档
    result = collection.update_one({'name': 'Alice'}, {'$set': {'age': 31}})

    # 更新多个文档
    results = collection.update_many({'age': {'$gt': 25}}, {'$inc': {'age': 1}})

    这里 '$set' 操作符用于设定字段的值,'$inc' 用于增加一个值。

  • 删除文档

    从集合中删除一个或多个文档:

    1
    2
    3
    4
    5
    # 删除单个文档
    result = collection.delete_one({'name': 'Bob'})

    # 删除多个文档
    results = collection.delete_many({'age': {'$lt': 30}})

    其中 '$lt' 是一个查询操作符,意味着 “小于”。

  • 索引

    在集合上创建索引以提高查询效率:

    1
    2
    # 在'name'字段上创建索引
    index_result = collection.create_index([('name', pymongo.ASCENDING)])
  • 关闭连接

    在所有操作完成后,关闭客户端连接:

    1
    client.close()
  • 综合示例

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    from pymongo import MongoClient

    # 假设你已经安装了pymongo: pip install pymongo

    # 连接MongoDB,假设MongoDB在本地运行,默认端口27017
    client = MongoClient('mongodb://localhost:27017/')

    # 选择数据库'mydatabase',如果它不存在,将在第一次插入数据时自动创建
    db = client['mydatabase']

    # 选择集合(相当于关系数据库的表)'users'
    collection = db['users']

    # 插入一个文档(相当于关系数据库的记录)
    user1 = {'name': 'Alice', 'age': 25}
    collection.insert_one(user1)

    # 插入多个文档
    users = [
    {'name': 'Bob', 'age': 30},
    {'name': 'Charlie', 'age': 35}
    ]
    collection.insert_many(users)

    # 查询单个文档
    print(collection.find_one({'name': 'Alice'}))

    # 查询所有文档
    for user in collection.find():
    print(user)

    # 更新文档
    collection.update_one({'name': 'Alice'}, {'$set': {'age': 26}})

    # 删除文档
    collection.delete_one({'name': 'Bob'})

    # 创建索引
    collection.create_index([('name', 1)])

    # 关闭MongoDB连接
    client.close()

    这个脚本演示了以下操作:

    1. 连接到本地运行的 MongoDB 实例。
    2. 选择或创建一个名为 mydatabase 的数据库。
    3. 选择或创建一个名为 users 的集合。
    4. users 集合中插入一个单独的文档。
    5. users 集合中插入多个文档。
    6. 执行查询以寻找名为 "Alice" 的文档。
    7. 遍历并打印出 users 集合中的所有文档。
    8. 更新名为 "Alice" 的文档的年龄。
    9. 删除名为 "Bob" 的文档。
    10. name 字段上创建一个索引以提高查询性能。
    11. 关闭与 MongoDB 的连接。

友情链接