【Python】PyMongo:MongoDB操作

MongoDB 是一种NoSQL(非关系型)数据库,它以**文档(document)**的形式存储数据,而不是传统的表格形式。MongoDB 是开源的、高效的,尤其适用于需要处理大量数据和快速变化的数据场景。它的设计目标是提供灵活性、可扩展性和高性能。

使用 Docker 部署

拉取 MongoDB Docker 镜像

首先,您需要从 Docker Hub 上拉取 MongoDB 官方镜像。

bash 复制代码
docker pull mongo

这将下载最新版本的 MongoDB 镜像。如果您需要特定版本,可以在命令后指定版本号,例如 mongo:4.4

运行 MongoDB 容器

使用以下命令启动 MongoDB 容器:

bash 复制代码
docker run -d --name mongodb -p 27017:27017 -v ~/data/mongo:/data/db mongo
  • -d:以后台模式运行容器。
  • --name mongodb:指定容器名称为 mongodb,你可以根据需要更改名称。
  • -p 27017:27017:将主机的 27017 端口映射到容器中的 27017 端口(MongoDB 的默认端口)。
  • -v ~/data/mongo:/data/db:将本地目录 ~/data/mongo 挂载到容器的 /data/db,用于持久化 MongoDB 数据。如果不指定,MongoDB 容器中的数据不会持久化。

验证 MongoDB 是否启动

执行以下命令查看 MongoDB 容器的运行状态:

bash 复制代码
docker ps

您应该能看到 mongodb 容器在运行,并且其 27017 端口已暴露到主机。

连接到 MongoDB

现在,MongoDB 已经运行,您可以使用 MongoDB 客户端工具(如 mongo shell、MongoDB Compass)连接到数据库。

  • 使用 Mongo Shell 连接(确保你有安装 mongo 客户端):

    bash 复制代码
    mongo --host 127.0.0.1 --port 27017
  • 或者通过 Python(pymongo)连接

    python 复制代码
    from pymongo import MongoClient
    client = MongoClient('mongodb://localhost:27017/')

配置用户名和密码(可选)

如果您需要启用认证来保护 MongoDB,可以在启动容器时添加环境变量设置用户名和密码。

bash 复制代码
docker run -d --name mongodb \
  -p 27017:27017 \
  -v ~/data/mongo:/data/db \
  -e MONGO_INITDB_ROOT_USERNAME=admin \
  -e MONGO_INITDB_ROOT_PASSWORD=admin123 \
  mongo

在这种情况下,您需要使用设置的用户名和密码连接到 MongoDB:

bash 复制代码
mongo --username admin --password admin123 --authenticationDatabase admin

检查日志

如果你遇到问题或想要查看 MongoDB 容器的日志,可以使用以下命令:

bash 复制代码
docker logs mongodb

停止和删除 MongoDB 容器

  • 停止容器

    bash 复制代码
    docker stop mongodb
  • 删除容器

    bash 复制代码
    docker rm mongodb

连接 MongoDB 数据库

在开始任何数据库操作之前,您需要先建立与 MongoDB 的连接。MongoClientPyMongo 中的主要接口,用于与 MongoDB 实例通信。

python 复制代码
from pymongo import MongoClient

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

# 选择数据库
db = client['my_database']

内存中模拟部署

mongomock 是一个模拟 MongoDB 的 Python 库,允许您在内存中创建 MongoDB 的操作环境,而无需真正的 MongoDB 服务器。mongomock 模拟了 MongoDB 的大部分操作,适用于测试和开发环境。

安装 mongomock

首先,安装 mongomock 库:

bash 复制代码
pip install mongomock

连接内存中的 MongoDB

要在内存中连接 mongomock,您只需使用 mongomock.MongoClient() 来替代实际的 MongoDB 连接。这样所有数据都将保存在内存中,而无需连接到物理的 MongoDB 服务器。

python 复制代码
import mongomock
from pymongo import MongoClient

# 使用 mongomock 代替 MongoDB 连接
client = mongomock.MongoClient()

数据库操作

MongoDB 中的数据库操作是管理和组织数据的基础。在 PyMongo 中,我们可以轻松进行数据库的创建、选择、列出和删除等操作。

列出所有数据库

要查看 MongoDB 实例中的所有数据库,可以使用 list_database_names() 方法。这会返回一个包含数据库名称的列表。

python 复制代码
from pymongo import MongoClient

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

# 列出所有数据库
databases = client.list_database_names()
print(databases)
  • 输出示例 :

    python 复制代码
    ['admin', 'local', 'my_database']

创建或选择数据库

MongoDB 是无模式的(schema-less),这意味着您不需要明确地创建数据库,只要您向该数据库中插入文档,它就会自动创建。要选择数据库,您只需通过 client['database_name'] 访问它。

python 复制代码
# 选择数据库(如果不存在,在插入文档时将自动创建)
db = client['my_database']

# 检查当前数据库名称
print(db.name)  # 输出: my_database

此时,my_database 数据库实际上还没有创建,直到您向其中插入数据为止。

删除数据库

如果您需要删除某个数据库,可以使用 drop_database() 方法。它会从 MongoDB 实例中删除整个数据库及其包含的所有数据。

python 复制代码
# 删除名为 'my_database' 的数据库
client.drop_database('my_database')
  • 注意: 该操作是不可逆的,执行后所有数据将被删除。

集合操作

集合(collection)是 MongoDB 中用于存储文档的类似表的结构。在 PyMongo 中,您可以轻松操作集合,进行创建、列出和删除等操作。

列出所有集合

要查看当前数据库中的所有集合,可以使用 list_collection_names() 方法。这将返回该数据库中所有集合的名称。

python 复制代码
# 选择数据库
db = client['my_database']

# 列出所有集合
collections = db.list_collection_names()
print(collections)
  • 输出示例 :

    python 复制代码
    ['users', 'orders', 'products']

创建或选择集合

与数据库一样,MongoDB 也不会在创建集合时进行强制检查。您只需使用 db['collection_name'] 来引用集合,MongoDB 会在插入文档时自动创建它。

python 复制代码
# 选择集合(如果不存在,将在插入数据时自动创建)
collection = db['users']

# 检查当前集合名称
print(collection.name)  # 输出: users

如果集合不存在,在第一次插入文档时将会自动创建。

删除集合

您可以使用 drop() 方法来删除集合。这将删除集合以及其中的所有数据。

python 复制代码
# 删除集合 'users'
db.drop_collection('users')
  • 注意: 该操作是不可逆的,删除集合后,其包含的所有文档都将被永久删除。

文档操作

MongoDB 中的文档是数据的基本单元,每个文档都是一个 BSON 格式的键值对集合。在 PyMongo 中,您可以进行各种文档操作,包括插入、删除、更新和查询。以下是这些操作的详细说明和示例。

插入文档

文档的插入操作可以通过 insert_one()insert_many() 方法来完成。

  • 插入单个文档

    使用 insert_one() 方法向集合中插入单个文档。

    python 复制代码
    from pymongo import MongoClient
    
    # 连接到 MongoDB
    client = MongoClient('mongodb://localhost:27017/')
    db = client['my_database']
    collection = db['my_collection']
    
    # 插入单个文档
    document = {"name": "Alice", "age": 25, "city": "New York"}
    result = collection.insert_one(document)
    
    # 获取插入的文档的 ID
    print("Inserted document ID:", result.inserted_id)
  • 插入多个文档

    使用 insert_many() 方法向集合中插入多个文档。

    python 复制代码
    documents = [
        {"name": "Bob", "age": 30, "city": "Los Angeles"},
        {"name": "Charlie", "age": 35, "city": "Chicago"}
    ]
    result = collection.insert_many(documents)
    
    # 获取插入的文档的 ID 列表
    print("Inserted document IDs:", result.inserted_ids)

删除文档

删除文档可以通过 delete_one()delete_many() 方法进行。

  • 删除单个文档

    使用 delete_one() 方法删除集合中符合条件的第一个文档。

    python 复制代码
    result = collection.delete_one({"name": "Alice"})
    
    # 输出删除操作的结果
    print("Number of documents deleted:", result.deleted_count)
  • 删除多个文档

    使用 delete_many() 方法删除集合中所有符合条件的文档。

    python 复制代码
    result = collection.delete_many({"age": {"$lt": 30}})  # 删除年龄小于 30 的文档
    
    # 输出删除操作的结果
    print("Number of documents deleted:", result.deleted_count)

更新文档

更新文档可以通过 update_one()update_many() 方法进行。update() 方法也可以实现,但推荐使用 update_one()update_many()

  • 更新单个文档

    使用 update_one() 方法更新集合中符合条件的第一个文档。

    python 复制代码
    result = collection.update_one(
        {"name": "Bob"},
        {"$set": {"age": 31}}
    )
    
    # 输出更新操作的结果
    print("Number of documents matched:", result.matched_count)
    print("Number of documents modified:", result.modified_count)
  • 更新多个文档

    使用 update_many() 方法更新集合中所有符合条件的文档。

    python 复制代码
    result = collection.update_many(
        {"city": "Chicago"},
        {"$set": {"city": "Chi-Town"}}
    )
    
    # 输出更新操作的结果
    print("Number of documents matched:", result.matched_count)
    print("Number of documents modified:", result.modified_count)
  • 使用更新操作符

    MongoDB 提供了多种更新操作符,例如 $inc$set$unset 等。

    python 复制代码
    # 增加年龄字段的值
    collection.update_one({"name": "Charlie"}, {"$inc": {"age": 1}})
    
    # 设置新的字段值
    collection.update_one({"name": "Charlie"}, {"$set": {"status": "active"}})
    
    # 删除字段
    collection.update_one({"name": "Charlie"}, {"$unset": {"status": ""}})

查询文档

查询文档是 MongoDB 操作中最常见的任务之一。PyMongo 提供了强大的查询功能,通过 find_one()find() 方法可以执行各种查询操作。

  • 查找单个文档

    使用 find_one() 方法查找集合中符合条件的第一个文档。如果没有匹配的文档,则返回 None

    python 复制代码
    document = collection.find_one({"name": "Alice"})
    print(document)
  • 查找多个文档

    使用 find() 方法查找集合中所有符合条件的文档。返回的是一个游标对象,可以通过迭代来访问结果。

    python 复制代码
    cursor = collection.find({"age": {"$gt": 25}})  # 查找年龄大于 25 的所有文档
    for document in cursor:
        print(document)
  • 指定返回字段

    使用投影来指定返回的字段。如果您只需要某些字段,可以在查询中指定。

    python 复制代码
    cursor = collection.find({"age": {"$gt": 25}}, {"name": 1, "city": 1, "_id": 0})
    for document in cursor:
        print(document)
  • 使用排序和限制结果

    使用 sort() 方法对查询结果进行排序,使用 limit() 方法限制结果数量。

    python 复制代码
    # 按年龄升序排序,限制结果为前 5 个
    cursor = collection.find().sort("age", pymongo.ASCENDING).limit(5)
    for document in cursor:
        print(document)
  • 使用查询操作符

    MongoDB 支持丰富的查询操作符,例如 $eq$ne$gt$lt$in$nin 等。

    以下是 MongoDB 查询操作符的功能与使用的详细表格:

    操作符 功能 示例用法
    $eq 等于 { "age": { "$eq": 25 } } 查找年龄等于 25 的文档。
    $ne 不等于 { "age": { "$ne": 25 } } 查找年龄不等于 25 的文档。
    $gt 大于 { "age": { "$gt": 25 } } 查找年龄大于 25 的文档。
    $gte 大于或等于 { "age": { "$gte": 25 } } 查找年龄大于或等于 25 的文档。
    $lt 小于 { "age": { "$lt": 25 } } 查找年龄小于 25 的文档。
    $lte 小于或等于 { "age": { "$lte": 25 } } 查找年龄小于或等于 25 的文档。
    $in 在指定值的数组中 { "age": { "$in": [25, 30, 35] } } 查找年龄在 25、30 或 35 中的文档。
    $nin 不在指定值的数组中 { "age": { "$nin": [25, 30, 35] } } 查找年龄不在 25、30 或 35 中的文档。
    $or 满足任意一个条件 { "$or": [ { "age": { "$lt": 25 } }, { "city": "New York" } ] } 查找年龄小于 25 或城市为 New York 的文档。
    $and 满足所有条件 { "$and": [ { "age": { "$gt": 25 } }, { "city": "New York" } ] } 查找年龄大于 25 且城市为 New York 的文档。
    $not 取反 { "age": { "$not": { "$gt": 25 } } } 查找年龄小于或等于 25 的文档。
    $exists 字段是否存在 { "name": { "$exists": true } } 查找包含 name 字段的文档。
    $type 字段的数据类型 { "age": { "$type": "int" } } 查找 age 字段数据类型为整数的文档。
    $regex 字段值匹配正则表达式 { "name": { "$regex": "^A", "$options": "i" } } 查找 name 字段以 "A" 开头的文档(不区分大小写)。
    $elemMatch 匹配数组中至少一个元素 { "scores": { "$elemMatch": { "subject": "Math", "score": { "$gt": 80 } } } } 查找 scores 数组中包含至少一个分数大于 80 且科目为 Math 的文档。
    $all 数组包含所有指定的值 { "tags": { "$all": ["urgent", "finance"] } } 查找 tags 数组中同时包含 "urgent" 和 "finance" 的文档。
    $size 数组的长度 { "items": { "$size": 3 } } 查找 items 数组长度为 3 的文档。
    python 复制代码
    # 查找年龄等于 30 的文档
    cursor = collection.find({"age": {"$eq": 30}})
    for document in cursor:
        print(document)
    
    # 查找年龄在 20 到 30 之间的文档
    cursor = collection.find({"age": {"$gt": 20, "$lt": 30}})
    for document in cursor:
        print(document)
    
    # 查找城市在指定列表中的文档
    cursor = collection.find({"city": {"$in": ["New York", "Los Angeles"]}})
    for document in cursor:
        print(document)

嵌套文档操作

插入嵌套文档

使用 insert_one() 方法可以将嵌套文档直接插入集合中。

python 复制代码
from pymongo import MongoClient

client = MongoClient('mongodb://localhost:27017/')
db = client['my_database']
collection = db['my_collection']

# 插入一个嵌套文档
document = {
    "name": "Alice",
    "address": {
        "city": "New York",
        "zipcode": "10001"
    }
}
collection.insert_one(document)

查询嵌套文档

MongoDB 支持通过点符号来查询嵌套文档中的字段。

查询嵌套字段时,可以直接通过字段路径进行精确查询。例如,查找 address.city"New York" 的文档:

python 复制代码
query = {"address.city": "New York"}
cursor = collection.find(query)

for document in cursor:
    print(document)

如果文档中包含嵌套文档数组,可以通过点符号和条件组合来查询。例如,查找 addresses 数组中包含 city"San Francisco" 的文档:

python 复制代码
query = {"addresses.city": "San Francisco"}
cursor = collection.find(query)

for document in cursor:
    print(document)

更新嵌套文档

通过点符号和 $set 可以更新嵌套文档中的字段。

更新 address.city"Los Angeles" 的操作如下:

python 复制代码
collection.update_one(
    {"name": "Alice"},
    {"$set": {"address.city": "Los Angeles"}}
)

通过 $ 操作符可以更新数组中的嵌套字段。如下所示,更新 addresses 数组中 city"San Francisco"zipcode

python 复制代码
collection.update_one(
    {"addresses.city": "San Francisco"},
    {"$set": {"addresses.$.zipcode": "94105"}}
)

删除嵌套文档

使用 $unset 可以删除嵌套文档中的字段。

删除 address.zipcode 字段的操作如下:

python 复制代码
collection.update_one(
    {"name": "Alice"},
    {"$unset": {"address.zipcode": ""}}
)

通过 $pull 操作符可以从数组中删除特定的嵌套文档。例如,删除 addresses 数组中 city"San Francisco" 的文档:

python 复制代码
collection.update_one(
    {"name": "Bob"},
    {"$pull": {"addresses": {"city": "San Francisco"}}}
)

索引操作

索引在 MongoDB 中用于加快查询速度,PyMongo 提供了创建和管理索引的功能。

创建索引

可以为集合中的字段创建索引:

python 复制代码
collection.create_index([("name", 1)])  # 1 代表升序索引

列出索引

您可以列出集合中所有的索引:

python 复制代码
indexes = collection.list_indexes()
for index in indexes:
    print(index)

删除索引

删除指定的索引:

python 复制代码
collection.drop_index("name_1")  # "name_1" 是索引名称

聚合操作

MongoDB 提供了强大的聚合管道操作,用于处理数据的复杂查询和转换。PyMongo 支持 aggregate() 方法来执行聚合查询。

python 复制代码
pipeline = [
    {"$match": {"age": {"$gt": 25}}},  # 过滤条件
    {"$group": {"_id": "$city", "average_age": {"$avg": "$age"}}}  # 按照城市分组,计算平均年龄
]
result = collection.aggregate(pipeline)
for doc in result:
    print(doc)

事务支持

对于涉及多个操作的原子性需求,MongoDB 支持事务。在事务中,所有的操作要么成功执行,要么失败回滚。

python 复制代码
with client.start_session() as session:
    with session.start_transaction():
        collection.update_one({"name": "Bob"}, {"$set": {"age": 32}}, session=session)
        collection.update_one({"name": "Charlie"}, {"$set": {"age": 36}}, session=session)

GridFS 文件存储

MongoDB 支持存储大文件或二进制数据,PyMongo 提供了 GridFS 用于存储超过 16MB 的大文件。

上传文件到 GridFS

python 复制代码
from gridfs import GridFS

fs = GridFS(db)
file_id = fs.put(b"Some large binary data")

下载文件

python 复制代码
file_data = fs.get(file_id).read()
相关推荐
小馒头学python1 分钟前
机器学习是什么?AIGC又是什么?机器学习与AIGC未来科技的双引擎
人工智能·python·机器学习
k09333 分钟前
sourceTree回滚版本到某次提交
开发语言·前端·javascript
神奇夜光杯11 分钟前
Python酷库之旅-第三方库Pandas(202)
开发语言·人工智能·python·excel·pandas·标准库及第三方库·学习与成长
Themberfue13 分钟前
Java多线程详解⑤(全程干货!!!)线程安全问题 || 锁 || synchronized
java·开发语言·线程·多线程·synchronized·
plmm烟酒僧14 分钟前
Windows下QT调用MinGW编译的OpenCV
开发语言·windows·qt·opencv
千天夜22 分钟前
使用UDP协议传输视频流!(分片、缓存)
python·网络协议·udp·视频流
测试界的酸菜鱼26 分钟前
Python 大数据展示屏实例
大数据·开发语言·python
羊小猪~~30 分钟前
神经网络基础--什么是正向传播??什么是方向传播??
人工智能·pytorch·python·深度学习·神经网络·算法·机器学习
晨曦_子画35 分钟前
编程语言之战:AI 之后的 Kotlin 与 Java
android·java·开发语言·人工智能·kotlin
Black_Friend43 分钟前
关于在VS中使用Qt不同版本报错的问题
开发语言·qt