目录
MongoDB简介
MongoDB是一个基于分布式文件存储的开源NoSQL数据库,由C++语言编写。它采用文档存储格式(BSON,一种类似JSON的二进制存储格式),具有高性能、高可用性和易扩展性等特点。与传统的关系型数据库相比,MongoDB具有以下优势:
- 无固定表结构,文档格式灵活
- 水平扩展能力强,适合大数据量存储
- 支持丰富的查询语言
- 内置复制和故障转移功能
- 支持多种编程语言驱动
安装与配置
安装MongoDB
-
Windows安装:
- 从MongoDB官网下载.msi安装包
- 运行安装向导,选择"Complete"完整安装
- 安装完成后,MongoDB默认安装在
C:\Program Files\MongoDB
目录下 - 需要手动创建数据存储目录
C:\data\db
-
MacOS安装:
brew tap mongodb/brew brew install mongodb-community
启动服务:
brew services start mongodb-community
-
Linux安装(Ubuntu):
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv 9DA31620334BD75D9DCB49F368818C72E52529D4 echo "deb [ arch=amd64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-org/4.0 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-4.0.list sudo apt-get update sudo apt-get install -y mongodb-org
启动服务:
sudo systemctl start mongod
安装Python驱动
MongoDB官方提供了Python驱动pymongo
:
pip install pymongo
如果需要使用更高级的功能,可以安装包含额外工具的pymongo[srv]
:
pip install pymongo[srv]
基本操作
连接数据库
from pymongo import MongoClient
# 连接本地MongoDB服务
client = MongoClient('mongodb://localhost:27017/')
# 连接远程MongoDB服务
# client = MongoClient('mongodb://username:password@host:port/database')
# 获取或创建数据库
db = client['test_database']
# 获取或创建集合(类似关系型数据库中的表)
collection = db['test_collection']
插入文档
# 插入单个文档
document = {
"name": "张三",
"age": 28,
"skills": ["Python", "MongoDB", "Linux"],
"address": {
"city": "北京",
"street": "朝阳区"
}
}
insert_result = collection.insert_one(document)
print("插入文档ID:", insert_result.inserted_id)
# 插入多个文档
documents = [
{"name": "李四", "age": 25, "skills": ["Java", "MySQL"]},
{"name": "王五", "age": 30, "skills": ["JavaScript", "React"]},
{"name": "赵六", "age": 22, "skills": ["C++", "Algorithm"]}
]
insert_results = collection.insert_many(documents)
print("插入文档IDs:", insert_results.inserted_ids)
查询文档
# 查询单个文档
document = collection.find_one({"name": "张三"})
print("查询结果:", document)
# 查询多个文档
cursor = collection.find({"age": {"$gt": 25}}) # 查询年龄大于25的文档
for doc in cursor:
print(doc)
# 高级查询
# $and: 与操作
# $or: 或操作
# $in: 包含
# $lt/$lte/$gt/$gte: 比较操作
# $regex: 正则表达式
cursor = collection.find({
"$and": [
{"age": {"$gte": 25}},
{"skills": {"$in": ["Python"]}}
]
})
更新文档
# 更新单个文档
update_result = collection.update_one(
{"name": "张三"},
{"$set": {"age": 29, "address.city": "上海"}}
)
print("匹配文档数:", update_result.matched_count)
print("修改文档数:", update_result.modified_count)
# 更新多个文档
update_result = collection.update_many(
{"age": {"$lt": 30}},
{"$inc": {"age": 1}} # 年龄加1
)
print("匹配文档数:", update_result.matched_count)
print("修改文档数:", update_result.modified_count)
删除文档
# 删除单个文档
delete_result = collection.delete_one({"name": "赵六"})
print("删除文档数:", delete_result.deleted_count)
# 删除多个文档
delete_result = collection.delete_many({"age": {"$lt": 25}})
print("删除文档数:", delete_result.deleted_count)
高级操作
索引操作
# 创建索引
collection.create_index([("name", pymongo.ASCENDING)], unique=True)
# 创建复合索引
collection.create_index([("name", pymongo.ASCENDING), ("age", pymongo.DESCENDING)])
# 获取索引信息
indexes = collection.list_indexes()
for index in indexes:
print(index)
# 删除索引
collection.drop_index("name_1")
聚合管道
pipeline = [
{"$match": {"age": {"$gt": 25}}}, # 筛选阶段
{"$group": {"_id": "$address.city", "count": {"$sum": 1}}}, # 分组阶段
{"$sort": {"count": -1}}, # 排序阶段
{"$limit": 5} # 限制阶段
]
results = collection.aggregate(pipeline)
for result in results:
print(result)
批量操作
from pymongo import UpdateOne, DeleteOne
# 批量写入操作
operations = [
UpdateOne({"name": "张三"}, {"$set": {"age": 30}}),
DeleteOne({"name": "李四"}),
UpdateOne({"name": "王五"}, {"$inc": {"age": 1}}, upsert=True)
]
result = collection.bulk_write(operations)
print("操作结果:", result.bulk_api_result)
性能优化
-
合理使用索引:
- 为常用查询字段创建索引
- 为排序字段创建索引
- 避免创建过多索引,影响写入性能
-
查询优化:
# 使用投影减少返回字段 collection.find({"age": {"$gt": 25}}, {"name": 1, "age": 1, "_id": 0}) # 限制返回文档数量 collection.find().limit(10) # 使用hint强制使用特定索引 collection.find({"name": "张三"}).hint([("name", 1)])
-
批量操作:
- 使用
insert_many
替代多次insert_one
- 使用
bulk_write
批量执行更新/删除操作
- 使用
实战案例
用户管理系统
from datetime import datetime
from pymongo import MongoClient, ASCENDING, DESCENDING
class UserManager:
def __init__(self, db_name='user_db'):
self.client = MongoClient('mongodb://localhost:27017/')
self.db = self.client[db_name]
self.users = self.db['users']
# 创建索引
self.users.create_index([("username", ASCENDING)], unique=True)
self.users.create_index([("email", ASCENDING)], unique=True)
def add_user(self, username, email, password):
user = {
"username": username,
"email": email,
"password": password,
"created_at": datetime.utcnow(),
"last_login": None,
"status": "active"
}
try:
result = self.users.insert_one(user)
return result.inserted_id
except Exception as e:
print(f"添加用户失败: {e}")
return None
def find_user(self, username=None, email=None):
query = {}
if username:
query["username"] = username
if email:
query["email"] = email
return self.users.find_one(query)
def update_user(self, user_id, updates):
result = self.users.update_one(
{"_id": user_id},
{"$set": updates}
)
return result.modified_count > 0
def delete_user(self, user_id):
result = self.users.delete_one({"_id": user_id})
return result.deleted_count > 0
def list_users(self, page=1, per_page=10):
skip = (page - 1) * per_page
cursor = self.users.find().skip(skip).limit(per_page)
return list(cursor)
# 使用示例
if __name__ == "__main__":
manager = UserManager()
# 添加用户
user_id = manager.add_user("testuser", "test@example.com", "password123")
# 查询用户
user = manager.find_user(username="testuser")
print(user)
# 更新用户
manager.update_user(user_id, {"last_login": datetime.utcnow()})
# 删除用户
manager.delete_user(user_id)
日志分析系统
class LogAnalyzer:
def __init__(self, db_name='log_db'):
self.client = MongoClient('mongodb://localhost:27017/')
self.db = self.client[db_name]
self.logs = self.db['logs']
# 创建TTL索引,日志自动过期
self.logs.create_index([("timestamp", ASCENDING)], expireAfterSeconds=3600*24*7) # 7天后自动删除
def log_event(self, level, message, source=None, metadata=None):
log_entry = {
"level": level,
"message": message,
"source": source,
"metadata": metadata or {},
"timestamp": datetime.utcnow()
}
return self.logs.insert_one(log_entry).inserted_id
def get_logs(self, level=None, start_time=None, end_time=None, limit=100):
query = {}
if level:
query["level"] = level
if start_time or end_time:
query["timestamp"] = {}
if start_time:
query["timestamp"]["$gte"] = start_time
if end_time:
query["timestamp"]["$lte"] = end_time
return list(self.logs.find(query).sort("timestamp", DESCENDING).limit(limit))
def analyze_logs(self):
pipeline = [
{"$group": {
"_id": "$level",
"count": {"$sum": 1},
"last_time": {"$max": "$timestamp"},
"first_time": {"$min": "$timestamp"}
}},
{"$sort": {"count": -1}}
]
return list(self.logs.aggregate(pipeline))
# 使用示例
if __name__ == "__main__":
analyzer = LogAnalyzer()
# 记录日志
analyzer.log_event("INFO", "Application started", "main.py")
analyzer.log_event("ERROR", "Failed to connect to database", "db.py", {"retry_count": 3})
# 查询日志
logs = analyzer.get_logs(level="ERROR", limit=5)
print(logs)
# 分析日志
stats = analyzer.analyze_logs()
print(stats)
常见问题与解决方案
-
连接失败:
- 检查MongoDB服务是否启动
- 检查防火墙设置,确保端口27017开放
- 检查连接字符串是否正确
-
性能问题:
- 使用
explain()
方法分析查询性能 - 确保查询使用了适当的索引
- 考虑分片处理大数据集
- 使用
-
内存不足:
- 调整MongoDB的WiredTiger缓存大小
- 增加服务器内存
- 优化查询减少内存使用
-
数据一致性问题:
- 使用事务(需要MongoDB 4.0+)
- 合理设计文档结构减少跨文档操作
- 使用写关注(write concern)确保数据持久化
总结
通过本文,你应该已经掌握了使用Python操作MongoDB的基本方法和高级技巧。MongoDB作为一款流行的NoSQL数据库,在处理非结构化数据、快速开发和水平扩展方面具有明显优势。结合Python的强大生态,可以构建各种高效的数据处理应用。
在实际项目中,建议:
- 合理设计文档结构
- 为常用查询创建索引
- 使用批量操作提高性能
- 定期监控数据库性能
- 做好数据备份策略
希望这篇指南能帮助你快速上手Python与MongoDB的开发工作!
—————————常用命令以及T-SQL增删改查语句————————————–
查看表基本信息:db.getCollection(‘AUDCAD’).stats() 类似于MySql的EXPLAIN
倒序查询数据:db.getCollection(‘AUDCAD’).find({}).sort({field:-1})
show dbs; #查看全部数据库
show collections; #显示当前数据库中的集合(类似关系数据库中的表)
show users; #查看当前数据库的用户信息
use <db name="">; #切换数据库跟mysql一样
db;或者db.getName(); #查看当前所在数据库
db.help(); #显示数据库操作命令,里面有很多的命令
db.foo.help(); #显示集合操作命令,同样有很多的命令,foo指的是当前数据库下,一个叫foo的集合,并非真正意义上的命令
db.foo.find(); #对于当前数据库中的foo集合进行数据查找(由于没有条件,会列出所有数据)
db.foo.find( { a : 1 } ); #对于当前数据库中的foo集合进行查找,条件是数据中有一个属性叫a,且a的值为1
db.version(); #当前db版本
db.getMongo(); #查看当前db的连接机器地址
db.dropDatabase(); #删除数据库
增(insert)
1.单条数据插入
db.user.insert({“name”:”jack”,”age”:20})
2.批量数据插入采用命令行for循环
删(remove)
1.不带参数会删除全部数据,且不可恢复,切记!
db.user.remove({“name”:”joe”})
改(update)
1.整体更新
var model = db.user.findOne({“name”:”jack”})
model.age=30
db.user.update({“name”:”jack”},model)
2.局部更新
● inc修改器——比如我们做一个在线用户状态记录,每次修改会在原有的基础上自增𝑖𝑛𝑐修改器——比如我们做一个在线用户状态记录,每次修改会在原有的基础上自增inc指定的值,如果“文档”中没有此key,则会创建key
db.user.update({“name”:”jack”},{inc:{“age”:30}}) //年龄增加30 ●inc:{“age”:30}}) //年龄增加30 ●set修改器
db.user.update({“name”:”jack”},{$set:{“age”:10}}) //年龄变为10</db>
3.upsert操作 —— 如果没有查到,就在数据库里面新增一条,使用起来很简单,将update的第三个参数设为true即可。
4.批量更新 —— 在mongodb中如果匹配多条,默认的情况下只更新第一条,那么如果我们有需求必须批量更新,那么在mongodb中实现也是很简单的,在update的第四个参数中设为true即可
查(find)
1.查找key=value的数据
db.collection.find({ “key” : value })
2.key > value
db.collection.find({ “key” : { [Math Processing Error]gt: value } }) 3.key < value db.collection.find({ “key” : { $lt: value } }) 4.key >= value db.collection.find({ “key” : { $gte: value } }) 5.key <= value db.collection.find({ “key” : { $lte: value } }) 6.value1 < key <value2 db.collection.find({="" "key"="" :="" {="" $gt:="" value1="" ,="" $lt:="" value2="" }="" })="" 7.key="" <=""> value db.collection.find({ “key” : { $ne: value } }) 8.取模运算,条件相当于key % 10 == 1 即key除以10余数为1的 db.collection.find({ “key” : { $mod : [ 10 , 1 ] } }) 9.不属于,条件相当于key的值不属于[ 1, 2, 3 ]中任何一个 db.collection.find({ “key” : { $nin: [ 1, 2, 3 ] } }) 10.属于,条件相当于key等于[ 1, 2, 3 ]中任何一个 db.collection.find({ “key” : { $in: [ 1, 2, 3 ] } }) 11.size 数量、尺寸,条件相当于key的值的数量是1(key必须是数组,一个值的情况不能算是数量为1的数组)
db.collection.find({ “key” : { size: 1 } }) 12.size: 1 } }) 12.exists 字段存在,true返回存在字段key的数据,false返回不存在字度key的数据
db.collection.find({ “key” : { [Math Processing Error]exists : true|false } }) 13.正则,类似like;“i”忽略大小写,“m”支持多行.如joe会匹配出来 db.collection.find({ “name”:/^j/,”name”:/e$/ }) 14.or或 (注意:MongoDB 1.5.3后版本可用),符合条件a=1的或者符合条件b=2的数据都会查询出来
db.collection.find({ [Math Processing Error]or : [{a : 1}, {b : 2} ] }) 15.符合条件key=value ,同时符合其他两个条件中任意一个的数据 db.collection.find({ “key”: value , $or : [{ a : 1 } , { b : 2 }] }) 16.内嵌对象中的值匹配,注意:”key.subkey”必须加引号 db.collection.find({ “key.subkey” :value }) 17.这是一个与其他查询条件组合使用的操作符,不会单独使用。上述查询条件得到的结果集加上not之后就能获得相反的集合。
db.collection.find({ “key”: { not:/val.val𝑛𝑜𝑡:/𝑣𝑎𝑙.𝑣𝑎𝑙/i } })
18.$where中的value,就是我们非常熟悉,非常热爱的js
db.collection.find({ $where:function(){return this.name==”joe”} })</value2>
- 指定时间删除
db.getCollection(‘AUDCHF’).remove({“ctm”:{$lt:1534322144}}) - 设置过期时间(索引)
db.collection.createIndex({“createdTime”: 1},{expireAfterSeconds: 300})
其中,dollection表名,expireTime是索引所在的字段,为Date格式,expireAfterSeconds表示0秒之后过期。该方式,可以传入一个过期时间到数据库中,到了指定时间,数据即删除