Python连接与操作Mongo以及Mongo_MCP

MongoDB Atlas 连接与操作完整指南

📋 目录

🎯 项目概述

本文介绍一个基于 Python 的 MongoDB Atlas 连接管理器,提供完整的数据库操作功能,包括连接管理、CRUD 操作、索引管理和聚合查询。

主要特性

  • ✅ 自动连接管理
  • ✅ 完整的 CRUD 操作
  • ✅ 索引创建和管理
  • ✅ 聚合管道支持
  • ✅ 错误处理和日志记录
  • ✅ 类型安全的响应对象

🔧 环境配置

1. 安装依赖

pip install pymongo dnspython python-dotenv pydantic

2. 环境变量配置

创建 .env 文件:

MONGODB_URI=mongodb+srv://username:password@cluster.mongodb.net/?retryWrites=true&w=majority
LOG_LEVEL=INFO

3. 项目结构

mongo_atlas_mcp/
├── __init__.py
├── database.py      # 核心数据库管理器
└── models.py        # 数据模型定义

🏗️ 核心类解析

MongoAtlasManager 类

这是整个系统的核心类,负责 MongoDB Atlas 的连接管理和所有数据库操作。

初始化与连接

class MongoAtlasManager:
    def __init__(self):
        """初始化MongoDB Atlas管理器"""
        self.client: Optional[MongoClient] = None
        self._connect()
    
    def _connect(self) -> None:
        """连接到MongoDB Atlas"""
        try:
            mongodb_uri = os.getenv('MONGODB_URI')
            if not mongodb_uri:
                raise ValueError("MONGODB_URI环境变量未设置")
            
            self.client = MongoClient(mongodb_uri)
            # 测试连接
            self.client.admin.command('ping')
            logger.info("成功连接到MongoDB Atlas")
            
        except Exception as e:
            logger.error(f"连接MongoDB Atlas失败: {str(e)}")
            raise

连接管理方法

def get_database(self, database_name: str) -> Database:
    """获取数据库对象"""
    if not self.client:
        raise ConnectionError("MongoDB客户端未连接")
    return self.client[database_name]

def get_collection(self, database_name: str, collection_name: str) -> Collection:
    """获取集合对象"""
    database = self.get_database(database_name)
    return database[collection_name]

📊 数据库操作

1. 数据库管理

列出所有数据库

def list_databases(self) -> MongoResponse:
    """列出所有数据库"""
    try:
        databases = []
        for db_name in self.client.list_database_names():
            database_info = DatabaseInfo(
                name=db_name,
                size_on_disk=0,  # 避免权限问题
                empty=False
            )
            databases.append(database_info.model_dump())
        
        return MongoResponse(
            success=True,
            data=databases,
            count=len(databases),
            message="成功列出数据库"
        )
    except Exception as e:
        logger.error(f"列出数据库失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=str(e),
            message="列出数据库失败"
        )

列出集合

def list_collections(self, database_name: str) -> MongoResponse:
    """列出指定数据库的所有集合"""
    try:
        database = self.get_database(database_name)
        collections = []
        
        for collection_name in database.list_collection_names():
            collection_info = CollectionInfo(
                name=collection_name,
                count=0,  # 避免权限问题
                size=0,
                avg_obj_size=0
            )
            collections.append(collection_info.model_dump())
        
        return MongoResponse(
            success=True,
            data=collections,
            count=len(collections),
            message="成功列出集合"
        )
    except Exception as e:
        logger.error(f"列出集合失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=str(e),
            message="列出集合失败"
        )

2. 文档操作

查询文档

def find_documents(self, database_name: str, collection_name: str, 
                  filter_dict: Dict[str, Any] = None, 
                  projection: Dict[str, Any] = None,
                  sort: List[tuple] = None,
                  limit: int = None,
                  skip: int = 0) -> MongoResponse:
    """查询文档"""
    try:
        collection = self.get_collection(database_name, collection_name)
        
        cursor = collection.find(
            filter=filter_dict or {},
            projection=projection
        )
        
        if sort:
            cursor = cursor.sort(sort)
        if skip:
            cursor = cursor.skip(skip)
        if limit:
            cursor = cursor.limit(limit)
        
        documents = list(cursor)
        
        # 序列化文档,将 ObjectId 转换为字符串
        serialized_documents = []
        for doc in documents:
            serialized_doc = {}
            for key, value in doc.items():
                if key == '_id':
                    serialized_doc[key] = str(value)
                else:
                    serialized_doc[key] = value
            serialized_documents.append(serialized_doc)
        
        return MongoResponse(
            success=True,
            data=serialized_documents,
            count=len(serialized_documents)
        )
    except PyMongoError as e:
        logger.error(f"查询文档失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"查询文档失败: {str(e)}"
        )

插入文档

def insert_document(self, database_name: str, collection_name: str, 
                   document: Dict[str, Any]) -> MongoResponse:
    """插入文档"""
    try:
        collection = self.get_collection(database_name, collection_name)
        result = collection.insert_one(document)
        
        return MongoResponse(
            success=True,
            data={"inserted_id": str(result.inserted_id)},
            count=1
        )
    except PyMongoError as e:
        logger.error(f"插入文档失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"插入文档失败: {str(e)}"
        )

更新文档

def update_document(self, database_name: str, collection_name: str,
                   filter_dict: Dict[str, Any], update_dict: Dict[str, Any],
                   upsert: bool = False, multi: bool = False) -> MongoResponse:
    """更新文档"""
    try:
        collection = self.get_collection(database_name, collection_name)
        
        if multi:
            result = collection.update_many(
                filter_dict, update_dict, upsert=upsert
            )
        else:
            result = collection.update_one(
                filter_dict, update_dict, upsert=upsert
            )
        
        return MongoResponse(
            success=True,
            data={
                "matched_count": result.matched_count,
                "modified_count": result.modified_count,
                "upserted_id": str(result.upserted_id) if result.upserted_id else None
            },
            count=result.modified_count
        )
    except PyMongoError as e:
        logger.error(f"更新文档失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"更新文档失败: {str(e)}"
        )

删除文档

def delete_document(self, database_name: str, collection_name: str,
                   filter_dict: Dict[str, Any], multi: bool = False) -> MongoResponse:
    """删除文档"""
    try:
        collection = self.get_collection(database_name, collection_name)
        
        if multi:
            result = collection.delete_many(filter_dict)
        else:
            result = collection.delete_one(filter_dict)
        
        return MongoResponse(
            success=True,
            data={"deleted_count": result.deleted_count},
            count=result.deleted_count
        )
    except PyMongoError as e:
        logger.error(f"删除文档失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"删除文档失败: {str(e)}"
        )

3. 聚合操作

执行聚合管道

def aggregate(self, database_name: str, collection_name: str,
              pipeline: List[Dict[str, Any]]) -> MongoResponse:
    """执行聚合管道"""
    try:
        collection = self.get_collection(database_name, collection_name)
        cursor = collection.aggregate(pipeline)
        results = list(cursor)
        
        return MongoResponse(
            success=True,
            data=results,
            count=len(results)
        )
    except PyMongoError as e:
        logger.error(f"执行聚合管道失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"执行聚合管道失败: {str(e)}"
        )

4. 索引管理

创建索引

def create_index(self, database_name: str, collection_name: str,
                 keys: List[tuple], name: str = None,
                 unique: bool = False, sparse: bool = False,
                 background: bool = True) -> MongoResponse:
    """创建索引"""
    try:
        collection = self.get_collection(database_name, collection_name)
        
        index_options = {
            "unique": unique,
            "sparse": sparse,
            "background": background
        }
        
        if name:
            index_options["name"] = name
        
        result = collection.create_index(keys, **index_options)
        
        return MongoResponse(
            success=True,
            data={"index_name": result},
            count=1
        )
    except PyMongoError as e:
        logger.error(f"创建索引失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"创建索引失败: {str(e)}"
        )

列出索引

def list_indexes(self, database_name: str, collection_name: str) -> MongoResponse:
    """列出集合的所有索引"""
    try:
        collection = self.get_collection(database_name, collection_name)
        indexes = []
        
        for index_info in collection.list_indexes():
            index_data = IndexInfo(
                name=index_info["name"],
                key=list(index_info["key"]),
                unique=index_info.get("unique", False),
                sparse=index_info.get("sparse", False),
                background=index_info.get("background", True)
            )
            indexes.append(index_data.model_dump())
        
        return MongoResponse(
            success=True,
            data=indexes,
            count=len(indexes)
        )
    except PyMongoError as e:
        logger.error(f"列出索引失败: {str(e)}")
        return MongoResponse(
            success=False,
            error=f"列出索引失败: {str(e)}"
        )

🧪 测试示例

1. 基本连接测试

from mongo_atlas_mcp.database import MongoAtlasManager

# 创建管理器实例
manager = MongoAtlasManager()

# 测试连接
print("✅ 连接成功")

2. 数据库操作测试

# 列出所有数据库
result = manager.list_databases()
print(f"数据库列表: {result.data}")

# 列出指定数据库的集合
result = manager.list_collections("test_db")
print(f"集合列表: {result.data}")

3. 文档操作测试

# 插入文档
document = {
    "name": "张三",
    "age": 28,
    "email": "zhangsan@example.com",
    "city": "北京",
    "hobbies": ["读书", "游泳", "编程"],
    "created_at": "2024-01-15T10:30:00Z",
    "is_active": True,
    "score": 95.5
}

result = manager.insert_document("test_db", "users", document)
print(f"插入结果: {result.data}")

# 查询文档
result = manager.find_documents("test_db", "users")
print(f"查询结果: {result.data}")

# 更新文档
filter_dict = {"name": "张三"}
update_dict = {"$set": {"age": 29, "score": 96.0}}
result = manager.update_document("test_db", "users", filter_dict, update_dict)
print(f"更新结果: {result.data}")

# 删除文档
result = manager.delete_document("test_db", "users", {"name": "张三"})
print(f"删除结果: {result.data}")

4. 聚合操作测试

# 聚合管道示例
pipeline = [
    {"$match": {"age": {"$gte": 25}}},
    {"$group": {"_id": "$city", "count": {"$sum": 1}, "avg_age": {"$avg": "$age"}}},
    {"$sort": {"count": -1}}
]

result = manager.aggregate("test_db", "users", pipeline)
print(f"聚合结果: {result.data}")

5. 索引操作测试

# 创建索引
keys = [("email", 1)]
result = manager.create_index("test_db", "users", keys, name="email_index", unique=True)
print(f"创建索引结果: {result.data}")

# 列出索引
result = manager.list_indexes("test_db", "users")
print(f"索引列表: {result.data}")

📊 测试输出示例

数据库列表输出

{
  "success": true,
  "data": [
    {
      "name": "sample_mflix",
      "size_on_disk": 0,
      "empty": false
    },
    {
      "name": "test_db",
      "size_on_disk": 0,
      "empty": false
    },
    {
      "name": "admin",
      "size_on_disk": 0,
      "empty": false
    },
    {
      "name": "local",
      "size_on_disk": 0,
      "empty": false
    }
  ],
  "count": 4,
  "message": "成功列出数据库"
}

集合列表输出

{
  "success": true,
  "data": [
    {
      "name": "users",
      "count": 0,
      "size": 0,
      "avg_obj_size": 0
    },
    {
      "name": "products",
      "count": 0,
      "size": 0,
      "avg_obj_size": 0
    }
  ],
  "count": 2,
  "message": "成功列出集合"
}

插入文档输出

{
  "success": true,
  "data": {
    "inserted_id": "6891e7622b3504a53dbe9e71"
  },
  "count": 1
}

查询文档输出

{
  "success": true,
  "data": [
    {
      "_id": "6891e7622b3504a53dbe9e71",
      "name": "张三",
      "age": 28,
      "email": "zhangsan@example.com",
      "city": "北京",
      "hobbies": ["读书", "游泳", "编程"],
      "created_at": "2024-01-15T10:30:00Z",
      "is_active": true,
      "score": 95.5
    }
  ],
  "count": 1
}

🎯 最佳实践

1. 连接管理

  • 使用环境变量管理连接字符串
  • 实现连接池管理
  • 添加连接重试机制

2. 错误处理

  • 使用 try-catch 包装所有数据库操作
  • 记录详细的错误日志
  • 返回统一的错误响应格式

3. 性能优化

  • 使用索引提升查询性能
  • 合理使用投影减少数据传输
  • 实现分页查询避免内存溢出

4. 安全性

  • 使用环境变量存储敏感信息
  • 实现用户权限验证
  • 防止 SQL 注入(MongoDB 天然支持)

5. 可维护性

  • 使用类型注解提高代码可读性
  • 实现统一的响应格式
  • 添加详细的文档注释

📝 总结

这个 MongoDB Atlas 连接管理器提供了完整的数据库操作功能,包括:

  • ✅ 自动连接管理
  • ✅ 完整的 CRUD 操作
  • ✅ 聚合查询支持
  • ✅ 索引管理功能
  • ✅ 统一的错误处理
  • ✅ 类型安全的响应

通过合理的设计和实现,可以轻松地在 Python 项目中集成 MongoDB Atlas,实现高效的数据存储和查询功能。

完整代码,包含相关的MCP

posted @ 2025-08-06 10:21  lyu6  阅读(22)  评论(0)    收藏  举报