[mongodb]python操作mongodb

42 阅读7分钟

我来提供一个完整的Python连接本地MongoDB的示例代码,包含基本的CRUD操作。

1. 首先安装必要的库

pip install pymongo

2. 完整示例代码

import pymongo
from pymongo import MongoClient
from datetime import datetime
from bson import ObjectId
import json
from typing import List, Dict, Any

class MongoDBManager:
    """MongoDB管理类"""
    
    def __init__(self, host='localhost', port=27017, username=None, password=None, database_name='mydatabase'):
        """
        初始化MongoDB连接
        
        Args:
            host: MongoDB主机地址,默认为localhost
            port: MongoDB端口,默认为27017
            username: 用户名(如果有认证)
            password: 密码(如果有认证)
            database_name: 数据库名称
        """
        try:
            # 构建连接字符串
            if username and password:
                # 有认证的连接
                connection_string = f"mongodb://{username}:{password}@{host}:{port}/"
                self.client = MongoClient(connection_string)
            else:
                # 无认证的连接(本地开发常用)
                self.client = MongoClient(host, port)
            
            # 测试连接
            self.client.admin.command('ping')
            print("✅ MongoDB连接成功!")
            
            # 选择数据库
            self.db = self.client[database_name]
            print(f"📁 已选择数据库: {database_name}")
            
        except Exception as e:
            print(f"❌ MongoDB连接失败: {e}")
            raise
    
    def list_databases(self):
        """列出所有数据库"""
        databases = self.client.list_database_names()
        print("📚 所有数据库:")
        for db in databases:
            print(f"  - {db}")
        return databases
    
    def list_collections(self):
        """列出当前数据库的所有集合"""
        collections = self.db.list_collection_names()
        print(f"📋 数据库 '{self.db.name}' 中的集合:")
        for col in collections:
            print(f"  - {col}")
        return collections
    
    def insert_one(self, collection_name: str, document: Dict[str, Any]):
        """
        插入单个文档
        
        Args:
            collection_name: 集合名称
            document: 要插入的文档
            
        Returns:
            插入的文档ID
        """
        try:
            collection = self.db[collection_name]
            result = collection.insert_one(document)
            print(f"✅ 文档插入成功,ID: {result.inserted_id}")
            return result.inserted_id
        except Exception as e:
            print(f"❌ 插入失败: {e}")
            return None
    
    def insert_many(self, collection_name: str, documents: List[Dict[str, Any]]):
        """
        插入多个文档
        
        Args:
            collection_name: 集合名称
            documents: 要插入的文档列表
            
        Returns:
            插入的文档ID列表
        """
        try:
            collection = self.db[collection_name]
            result = collection.insert_many(documents)
            print(f"✅ 批量插入成功,共 {len(result.inserted_ids)} 个文档")
            return result.inserted_ids
        except Exception as e:
            print(f"❌ 批量插入失败: {e}")
            return []
    
    def find_all(self, collection_name: str):
        """
        查询集合中的所有文档
        
        Args:
            collection_name: 集合名称
            
        Returns:
            文档列表
        """
        try:
            collection = self.db[collection_name]
            documents = list(collection.find())
            print(f"✅ 查询到 {len(documents)} 个文档")
            return documents
        except Exception as e:
            print(f"❌ 查询失败: {e}")
            return []
    
    def find_with_filter(self, collection_name: str, filter_query: Dict[str, Any]):
        """
        根据条件查询文档
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件
            
        Returns:
            匹配的文档列表
        """
        try:
            collection = self.db[collection_name]
            documents = list(collection.find(filter_query))
            print(f"✅ 查询到 {len(documents)} 个匹配的文档")
            return documents
        except Exception as e:
            print(f"❌ 条件查询失败: {e}")
            return []
    
    def find_one(self, collection_name: str, filter_query: Dict[str, Any]):
        """
        查询单个文档
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件
            
        Returns:
            单个文档或None
        """
        try:
            collection = self.db[collection_name]
            document = collection.find_one(filter_query)
            if document:
                print("✅ 找到匹配的文档")
            else:
                print("⚠️  未找到匹配的文档")
            return document
        except Exception as e:
            print(f"❌ 查询单个文档失败: {e}")
            return None
    
    def update_one(self, collection_name: str, filter_query: Dict[str, Any], update_data: Dict[str, Any]):
        """
        更新单个文档
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件
            update_data: 更新数据
            
        Returns:
            更新结果
        """
        try:
            collection = self.db[collection_name]
            # 使用 $set 操作符更新指定字段
            result = collection.update_one(filter_query, {"$set": update_data})
            print(f"✅ 更新成功,匹配到 {result.matched_count} 个文档,修改了 {result.modified_count} 个文档")
            return result
        except Exception as e:
            print(f"❌ 更新失败: {e}")
            return None
    
    def delete_one(self, collection_name: str, filter_query: Dict[str, Any]):
        """
        删除单个文档
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件
            
        Returns:
            删除结果
        """
        try:
            collection = self.db[collection_name]
            result = collection.delete_one(filter_query)
            print(f"✅ 删除成功,删除了 {result.deleted_count} 个文档")
            return result
        except Exception as e:
            print(f"❌ 删除失败: {e}")
            return None
    
    def delete_many(self, collection_name: str, filter_query: Dict[str, Any]):
        """
        删除多个文档
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件
            
        Returns:
            删除结果
        """
        try:
            collection = self.db[collection_name]
            result = collection.delete_many(filter_query)
            print(f"✅ 批量删除成功,删除了 {result.deleted_count} 个文档")
            return result
        except Exception as e:
            print(f"❌ 批量删除失败: {e}")
            return None
    
    def create_index(self, collection_name: str, field: str, unique=False):
        """
        创建索引
        
        Args:
            collection_name: 集合名称
            field: 索引字段
            unique: 是否唯一索引
            
        Returns:
            索引名称
        """
        try:
            collection = self.db[collection_name]
            index_result = collection.create_index([(field, pymongo.ASCENDING)], unique=unique)
            print(f"✅ 索引创建成功: {index_result}")
            return index_result
        except Exception as e:
            print(f"❌ 创建索引失败: {e}")
            return None
    
    def count_documents(self, collection_name: str, filter_query: Dict[str, Any] = None):
        """
        统计文档数量
        
        Args:
            collection_name: 集合名称
            filter_query: 查询条件(可选)
            
        Returns:
            文档数量
        """
        try:
            collection = self.db[collection_name]
            if filter_query:
                count = collection.count_documents(filter_query)
            else:
                count = collection.count_documents({})
            print(f"📊 文档数量: {count}")
            return count
        except Exception as e:
            print(f"❌ 统计失败: {e}")
            return 0
    
    def drop_collection(self, collection_name: str):
        """
        删除集合
        
        Args:
            collection_name: 集合名称
            
        Returns:
            True if successful, False otherwise
        """
        try:
            collection = self.db[collection_name]
            collection.drop()
            print(f"🗑️  集合 '{collection_name}' 已删除")
            return True
        except Exception as e:
            print(f"❌ 删除集合失败: {e}")
            return False
    
    def close_connection(self):
        """关闭数据库连接"""
        self.client.close()
        print("🔌 MongoDB连接已关闭")
    
    @staticmethod
    def pretty_print(documents: List[Dict[str, Any]]):
        """美化打印文档"""
        for i, doc in enumerate(documents):
            print(f"\n📄 文档 {i+1}:")
            # 处理ObjectId使其可序列化
            doc_copy = doc.copy()
            if '_id' in doc_copy:
                doc_copy['_id'] = str(doc_copy['_id'])
            print(json.dumps(doc_copy, indent=2, ensure_ascii=False))


# 使用示例
def main():
    # 1. 创建MongoDB管理器实例(连接本地MongoDB)
    mongo = MongoDBManager(
        host='localhost',
        port=27017,
        database_name='testdb'  # 数据库名称
    )
    
    try:
        # 2. 列出所有数据库和集合
        mongo.list_databases()
        
        # 3. 示例数据:用户信息
        users_collection = 'users'
        
        # 4. 插入单个文档
        print("\n1. 插入单个用户:")
        user1 = {
            "name": "张三",
            "age": 25,
            "email": "zhangsan@example.com",
            "city": "北京",
            "hobbies": ["读书", "游泳", "编程"],
            "created_at": datetime.now(),
            "is_active": True
        }
        user1_id = mongo.insert_one(users_collection, user1)
        
        # 5. 插入多个文档
        print("\n2. 批量插入用户:")
        users = [
            {
                "name": "李四",
                "age": 30,
                "email": "lisi@example.com",
                "city": "上海",
                "hobbies": ["旅游", "摄影"],
                "created_at": datetime.now(),
                "is_active": True
            },
            {
                "name": "王五",
                "age": 28,
                "email": "wangwu@example.com",
                "city": "广州",
                "hobbies": ["篮球", "音乐"],
                "created_at": datetime.now(),
                "is_active": True
            },
            {
                "name": "赵六",
                "age": 35,
                "email": "zhaoliu@example.com",
                "city": "北京",
                "hobbies": ["烹饪", "电影"],
                "created_at": datetime.now(),
                "is_active": False
            }
        ]
        user_ids = mongo.insert_many(users_collection, users)
        
        # 6. 查询所有文档
        print("\n3. 查询所有用户:")
        all_users = mongo.find_all(users_collection)
        mongo.pretty_print(all_users)
        
        # 7. 条件查询
        print("\n4. 查询北京的用户:")
        beijing_users = mongo.find_with_filter(users_collection, {"city": "北京"})
        mongo.pretty_print(beijing_users)
        
        # 8. 查询单个文档
        print("\n5. 查询年龄大于30的用户:")
        older_user = mongo.find_one(users_collection, {"age": {"$gt": 30}})
        if older_user:
            print(f"找到用户: {older_user['name']}, 年龄: {older_user['age']}")
        
        # 9. 更新文档
        print("\n6. 更新用户信息:")
        mongo.update_one(
            users_collection,
            {"name": "张三"},
            {"age": 26, "email": "zhangsan_new@example.com"}
        )
        
        # 10. 验证更新
        updated_user = mongo.find_one(users_collection, {"name": "张三"})
        if updated_user:
            print(f"更新后的用户: {updated_user['name']}, 年龄: {updated_user['age']}, 邮箱: {updated_user['email']}")
        
        # 11. 统计文档
        print("\n7. 统计活跃用户:")
        active_count = mongo.count_documents(users_collection, {"is_active": True})
        print(f"活跃用户数量: {active_count}")
        
        # 12. 删除文档
        print("\n8. 删除非活跃用户:")
        mongo.delete_many(users_collection, {"is_active": False})
        
        # 13. 再次统计
        remaining_count = mongo.count_documents(users_collection)
        print(f"剩余用户数量: {remaining_count}")
        
        # 14. 创建索引
        print("\n9. 创建索引:")
        mongo.create_index(users_collection, "email", unique=True)
        
        # 15. 列出所有集合
        mongo.list_collections()
        
    except Exception as e:
        print(f"程序执行出错: {e}")
    finally:
        # 16. 关闭连接
        mongo.close_connection()


# 高级用法示例:使用聚合管道
def advanced_example():
    """高级查询示例:使用聚合管道"""
    mongo = MongoDBManager(database_name='testdb')
    
    try:
        # 创建订单数据
        orders_collection = 'orders'
        
        # 插入一些订单数据
        orders = [
            {"customer": "张三", "amount": 150, "status": "completed", "date": datetime(2024, 1, 15)},
            {"customer": "李四", "amount": 200, "status": "completed", "date": datetime(2024, 1, 16)},
            {"customer": "张三", "amount": 300, "status": "pending", "date": datetime(2024, 1, 17)},
            {"customer": "王五", "amount": 100, "status": "completed", "date": datetime(2024, 1, 18)},
            {"customer": "李四", "amount": 250, "status": "completed", "date": datetime(2024, 1, 19)}
        ]
        
        mongo.insert_many(orders_collection, orders)
        
        # 使用聚合管道:按客户分组,计算总金额
        print("\n🔍 聚合查询:每个客户的总订单金额")
        pipeline = [
            {"$match": {"status": "completed"}},  # 只选择已完成的订单
            {"$group": {
                "_id": "$customer",  # 按客户分组
                "total_amount": {"$sum": "$amount"},  # 计算总金额
                "order_count": {"$sum": 1}  # 计算订单数量
            }},
            {"$sort": {"total_amount": -1}}  # 按总金额降序排序
        ]
        
        collection = mongo.db[orders_collection]
        results = list(collection.aggregate(pipeline))
        
        print("客户消费统计:")
        for result in results:
            print(f"  客户: {result['_id']}, 总金额: ¥{result['total_amount']}, 订单数: {result['order_count']}")
            
    finally:
        mongo.close_connection()


# 使用上下文管理器(推荐方式)
def with_context_manager():
    """使用上下文管理器管理连接"""
    from contextlib import contextmanager
    
    @contextmanager
    def get_mongo_connection():
        """获取MongoDB连接的上下文管理器"""
        mongo = None
        try:
            mongo = MongoDBManager(database_name='testdb')
            yield mongo
        finally:
            if mongo:
                mongo.close_connection()
    
    print("\n🎯 使用上下文管理器示例:")
    with get_mongo_connection() as mongo:
        # 在这里执行数据库操作
        users = mongo.find_all('users')
        print(f"当前有 {len(users)} 个用户")


if __name__ == "__main__":
    print("=" * 50)
    print("MongoDB CRUD 操作示例")
    print("=" * 50)
    
    # 运行基本示例
    main()
    
    print("\n" + "=" * 50)
    print("高级查询示例")
    print("=" * 50)
    
    # 运行高级示例
    advanced_example()
    
    # 运行上下文管理器示例
    with_context_manager()

3. 简化的快速使用版本

如果你需要一个更简洁的版本:

from pymongo import MongoClient
from datetime import datetime

# 1. 连接MongoDB
client = MongoClient('localhost', 27017)  # 默认配置

# 2. 选择数据库
db = client['mydatabase']

# 3. 选择集合(类似于SQL的表)
collection = db['users']

# 4. 插入数据
user_data = {
    "name": "张三",
    "age": 25,
    "email": "zhangsan@example.com",
    "created_at": datetime.now()
}
result = collection.insert_one(user_data)
print(f"插入成功,ID: {result.inserted_id}")

# 5. 查询数据
# 查询所有文档
all_users = collection.find()
for user in all_users:
    print(user)

# 条件查询
query = {"age": {"$gt": 20}}  # 年龄大于20
users = collection.find(query)
for user in users:
    print(user)

# 查询单个文档
user = collection.find_one({"name": "张三"})
print(f"找到用户: {user}")

# 6. 更新数据
collection.update_one(
    {"name": "张三"},
    {"$set": {"age": 26, "updated_at": datetime.now()}}
)

# 7. 删除数据
collection.delete_one({"name": "张三"})

# 8. 关闭连接
client.close()

4. 环境配置建议

创建 config.py 文件管理配置:

# config.py
class MongoDBConfig:
    HOST = 'localhost'
    PORT = 27017
    USERNAME = None
    PASSWORD = None
    DATABASE = 'mydatabase'
    
    # 连接字符串
    @classmethod
    def get_connection_string(cls):
        if cls.USERNAME and cls.PASSWORD:
            return f"mongodb://{cls.USERNAME}:{cls.PASSWORD}@{cls.HOST}:{cls.PORT}/"
        return f"mongodb://{cls.HOST}:{cls.PORT}/"

5. 常见查询操作符

# 常用查询操作符示例
query_examples = {
    # 等于
    "等于": {"name": "张三"},
    
    # 大于
    "大于": {"age": {"$gt": 20}},
    
    # 小于
    "小于": {"age": {"$lt": 30}},
    
    # 范围
    "范围": {"age": {"$gte": 20, "$lte": 30}},
    
    # 包含在数组中
    "包含": {"hobbies": {"$in": ["读书", "游泳"]}},
    
    # 不包含
    "不包含": {"hobbies": {"$nin": ["游戏"]}},
    
    # 存在字段
    "存在字段": {"email": {"$exists": True}},
    
    # 正则匹配
    "正则": {"name": {"$regex": "^张"}},  # 姓张的
    
    # 逻辑AND
    "AND": {"$and": [{"age": {"$gt": 20}}, {"city": "北京"}]},
    
    # 逻辑OR
    "OR": {"$or": [{"city": "北京"}, {"city": "上海"}]},
}

6. 启动MongoDB服务

在运行代码前,确保MongoDB服务已启动:

Windows:

# 启动MongoDB服务
net start MongoDB

macOS:

# 使用Homebrew安装后启动
brew services start mongodb-community

Linux:

# Ubuntu/Debian
sudo systemctl start mongod

# 检查状态
sudo systemctl status mongod

这个完整示例涵盖了MongoDB的基本操作,包括连接、CRUD操作、聚合查询等。你可以根据实际需求调整和扩展这些代码。