写在前面:掌握MongoDB的编程接口是开发MongoDB应用的基础。本篇将详细介绍如何使用Python(pymongo)和Node.js(mongoose)操作MongoDB,带您从理论走向实践。
文章目录
-
- 一、Python操作MongoDB
-
- [1.1 环境准备](#1.1 环境准备)
- [1.2 基础连接](#1.2 基础连接)
- [1.3 CRUD操作](#1.3 CRUD操作)
- [1.4 聚合操作](#1.4 聚合操作)
- [1.5 索引操作](#1.5 索引操作)
- 二、Node.js操作MongoDB
-
- [2.1 环境准备](#2.1 环境准备)
- [2.2 Mongoose基础](#2.2 Mongoose基础)
- [2.3 定义Schema](#2.3 定义Schema)
- [2.4 CRUD操作](#2.4 CRUD操作)
- [2.5 聚合管道](#2.5 聚合管道)
- 三、连接池与性能
-
- [3.1 Python连接池](#3.1 Python连接池)
- [3.2 Node.js连接池](#3.2 Node.js连接池)
- 四、实战:博客系统
-
- [4.1 项目结构](#4.1 项目结构)
- [4.2 数据模型](#4.2 数据模型)
- [4.3 API接口](#4.3 API接口)
- 五、错误处理
-
- [5.1 Python错误处理](#5.1 Python错误处理)
- [5.2 Node.js错误处理](#5.2 Node.js错误处理)
- 六、总结
一、Python操作MongoDB
1.1 环境准备
bash
# 安装pymongo
pip install pymongo
# 或者安装带异步支持的版本
pip install motor # 异步驱动
1.2 基础连接
python
from pymongo import MongoClient
# 方式1:基础连接
client = MongoClient('mongodb://localhost:27017/')
# 方式2:带认证连接
client = MongoClient(
'mongodb://username:password@localhost:27017/',
authSource='admin'
)
# 方式3:连接副本集
client = MongoClient(
'mongodb://localhost:27017,localhost:27018/?replicaSet=myReplSet'
)
# 选择数据库
db = client['myapp']
# 或
db = client.myapp
# 选择集合
users = db['users']
# 或
users = db.users
1.3 CRUD操作
python
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
db = client.myapp
users = db.users
# ========== 插入操作 ==========
# 插入单条
user = {
"username": "zhangsan",
"email": "zhang@example.com",
"age": 25,
"tags": ["python", "mongodb"]
}
result = users.insert_one(user)
print(f"插入ID: {result.inserted_id}")
# 插入多条
new_users = [
{"username": "lisi", "email": "li@example.com", "age": 28},
{"username": "wangwu", "email": "wang@example.com", "age": 30}
]
result = users.insert_many(new_users)
print(f"插入IDs: {result.inserted_ids}")
# ========== 查询操作 ==========
# 查询单条
user = users.find_one({"username": "zhangsan"})
print(user)
# 查询多条
for user in users.find({"age": {"$gt": 25}}):
print(user)
# 统计数量
count = users.count_documents({"age": {"$gt": 20}})
print(f"数量: {count}")
# 排序分页
for user in users.find().sort("age", -1).skip(0).limit(10):
print(user)
# ========== 更新操作 ==========
# 更新单条
result = users.update_one(
{"username": "zhangsan"},
{"$set": {"age": 26}}
)
print(f"修改数: {result.modified_count}")
# 更新多条
result = users.update_many(
{"age": {"$lt": 18}},
{"$set": {"status": "minor"}}
)
print(f"修改数: {result.modified_count}")
# ========== 删除操作 ==========
# 删除单条
result = users.delete_one({"username": "zhangsan"})
print(f"删除数: {result.deleted_count}")
# 删除多条
result = users.delete_many({"status": "inactive"})
print(f"删除数: {result.deleted_count}")
1.4 聚合操作
python
from pymongo import MongoClient
client = MongoClient('mongodb://localhost:27017/')
db = client.myapp
orders = db.orders
# 聚合管道
pipeline = [
{"$match": {"status": "completed"}},
{"$unwind": "$items"},
{
"$group": {
"_id": "$items.product",
"total_quantity": {"$sum": "$items.quantity"},
"total_revenue": {"$sum": {"$multiply": ["$items.price", "$items.quantity"]}}
}
},
{"$sort": {"total_revenue": -1}},
{"$limit": 10}
]
results = list(orders.aggregate(pipeline))
for r in results:
print(r)
1.5 索引操作
python
# 创建索引
users.create_index("username", unique=True)
users.create_index([("age", 1), ("city", -1)])
# 创建文本索引
users.create_index([("bio", "text")])
# 查看索引
for index in users.list_indexes():
print(index)
# 删除索引
users.drop_index("username_1")
二、Node.js操作MongoDB
2.1 环境准备
bash
# 初始化项目
npm init -y
# 安装mongoose
npm install mongoose
# 或安装mongodb(原生驱动)
npm install mongodb
2.2 Mongoose基础
javascript
const mongoose = require('mongoose');
// 连接MongoDB
mongoose.connect('mongodb://localhost:27017/myapp', {
useNewUrlParser: true,
useUnifiedTopology: true,
auth: {
user: 'username',
password: 'password'
}
});
// 连接成功
mongoose.connection.on('connected', () => {
console.log('MongoDB连接成功');
});
// 连接失败
mongoose.connection.on('error', (err) => {
console.error('MongoDB连接失败:', err);
});
2.3 定义Schema
javascript
const mongoose = require('mongoose');
const { Schema } = mongoose;
// 定义用户Schema
const userSchema = new Schema({
username: {
type: String,
required: true,
unique: true,
trim: true,
minlength: 3,
maxlength: 20
},
email: {
type: String,
required: true,
unique: true,
lowercase: true
},
age: {
type: Number,
min: 0,
max: 150
},
tags: [String],
status: {
type: String,
enum: ['active', 'inactive', 'banned'],
default: 'active'
},
profile: {
avatar: String,
bio: String
},
createdAt: {
type: Date,
default: Date.now
}
}, {
timestamps: true // 自动管理createdAt和updatedAt
});
// 创建索引
userSchema.index({ username: 1 });
userSchema.index({ email: 1 });
userSchema.index({ tags: 1 });
// 虚拟属性
userSchema.virtual('fullInfo').get(function() {
return `${this.username} - ${this.email}`;
});
// 方法
userSchema.methods.sayHello = function() {
return `你好,我是${this.username}`;
};
// 静态方法
userSchema.statics.findByUsername = function(username) {
return this.findOne({ username });
};
// 创建模型
const User = mongoose.model('User', userSchema);
module.exports = User;
2.4 CRUD操作
javascript
const User = require('./models/User');
async function main() {
// ========== 插入操作 ==========
// 创建单条
const user1 = new User({
username: 'zhangsan',
email: 'zhang@example.com',
age: 25,
tags: ['javascript', 'nodejs']
});
await user1.save();
// 直接创建
const user2 = await User.create({
username: 'lisi',
email: 'li@example.com',
age: 28
});
// 批量创建
const users = await User.insertMany([
{ username: 'wangwu', email: 'wang@example.com' },
{ username: 'zhaoliu', email: 'zhao@example.com' }
]);
// ========== 查询操作 ==========
// 查询单条
const user = await User.findOne({ username: 'zhangsan' });
const userById = await User.findById('507f1f77bcf86cd799439011');
// 查询多条
const youngUsers = await User.find({ age: { $lt: 30 } });
// 条件查询
const activeUsers = await User.find({ status: 'active' })
.sort({ createdAt: -1 })
.limit(10)
.select('username email');
// 统计数量
const count = await User.countDocuments({ status: 'active' });
// ========== 更新操作 ==========
// 更新单条
const updatedUser = await User.findOneAndUpdate(
{ username: 'zhangsan' },
{ $set: { age: 26 } },
{ new: true } // 返回更新后的文档
);
// 更新并保存
const user = await User.findOne({ username: 'lisi' });
user.age = 29;
await user.save();
// 批量更新
const result = await User.updateMany(
{ age: { $lt: 18 } },
{ $set: { status: 'minor' } }
);
// ========== 删除操作 ==========
// 删除单条
await User.findOneAndDelete({ username: 'zhangsan' });
// 批量删除
const deleteResult = await User.deleteMany({ status: 'banned' });
}
main().catch(console.error);
2.5 聚合管道
javascript
const Order = require('./models/Order');
async function aggregateExample() {
const pipeline = [
// 过滤已完成订单
{ $match: { status: 'completed' } },
// 展开订单项
{ $unwind: '$items' },
// 分组统计
{
$group: {
_id: '$items.product',
totalQuantity: { $sum: '$items.quantity' },
totalRevenue: { $sum: { $multiply: ['$items.price', '$items.quantity'] } }
}
},
// 排序
{ $sort: { totalRevenue: -1 } },
// 限制
{ $limit: 10 },
// 格式化输出
{
$project: {
product: '$_id',
totalQuantity: 1,
totalRevenue: 1,
_id: 0
}
}
];
const results = await Order.aggregate(pipeline);
console.log(results);
}
三、连接池与性能
3.1 Python连接池
python
from pymongo import MongoClient
from pymongo.pool import ConnectionPool
# 创建带连接池的客户端
client = MongoClient(
'mongodb://localhost:27017/',
maxPoolSize=50, # 最大连接数
minPoolSize=10, # 最小连接数
maxIdleTimeMS=30000, # 空闲超时
waitQueueTimeoutMS=30000 # 等待超时
)
3.2 Node.js连接池
javascript
// mongoose连接池配置
mongoose.connect('mongodb://localhost:27017/myapp', {
poolSize: 10, // 连接池大小
socketTimeoutMS: 45000,
serverSelectionTimeoutMS: 5000
});
// 或使用原生驱动
const { MongoClient } = require('mongodb');
const client = new MongoClient('mongodb://localhost:27017', {
poolSize: 10,
maxPoolSize: 50
});
四、实战:博客系统
4.1 项目结构
blog-app/
├── models/
│ ├── User.js
│ ├── Post.js
│ └── Comment.js
├── routes/
│ ├── users.js
│ ├── posts.js
│ └── comments.js
├── app.js
└── package.json
4.2 数据模型
javascript
// models/Post.js
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema({
title: {
type: String,
required: true,
trim: true
},
content: {
type: String,
required: true
},
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User',
required: true
},
tags: [String],
category: String,
status: {
type: String,
enum: ['draft', 'published', 'archived'],
default: 'draft'
},
views: {
type: Number,
default: 0
},
likes: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}],
comments: [{
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
content: String,
createdAt: { type: Date, default: Date.now }
}]
}, {
timestamps: true
});
// 文本搜索索引
postSchema.index({ title: 'text', content: 'text' });
module.exports = mongoose.model('Post', postSchema);
4.3 API接口
javascript
// routes/posts.js
const express = require('express');
const router = express.Router();
const Post = require('../models/Post');
// 获取文章列表
router.get('/', async (req, res) => {
const { page = 1, limit = 10, tag, category } = req.query;
const query = { status: 'published' };
if (tag) query.tags = tag;
if (category) query.category = category;
const posts = await Post.find(query)
.populate('author', 'username avatar')
.sort({ createdAt: -1 })
.skip((page - 1) * limit)
.limit(parseInt(limit));
const total = await Post.countDocuments(query);
res.json({
posts,
total,
page: parseInt(page),
pages: Math.ceil(total / limit)
});
});
// 获取单篇文章
router.get('/:id', async (req, res) => {
try {
const post = await Post.findByIdAndUpdate(
req.params.id,
{ $inc: { views: 1 } },
{ new: true }
).populate('author', 'username avatar');
res.json(post);
} catch (error) {
res.status(404).json({ error: '文章不存在' });
}
});
// 创建文章
router.post('/', async (req, res) => {
const { title, content, tags, category } = req.body;
const post = new Post({
title,
content,
tags,
category,
author: req.user._id // 假设已认证
});
await post.save();
res.status(201).json(post);
});
// 更新文章
router.put('/:id', async (req, res) => {
const post = await Post.findOneAndUpdate(
{ _id: req.params.id, author: req.user._id },
req.body,
{ new: true }
);
res.json(post);
});
// 删除文章
router.delete('/:id', async (req, res) => {
await Post.findOneAndDelete({
_id: req.params.id,
author: req.user._id
});
res.json({ message: '删除成功' });
});
// 搜索文章
router.get('/search', async (req, res) => {
const { q } = req.query;
const posts = await Post.find(
{ $text: { $search: q } },
{ score: { $meta: 'textScore' } }
)
.sort({ score: { $meta: 'textScore' } })
.limit(20);
res.json(posts);
});
module.exports = router;
五、错误处理
5.1 Python错误处理
python
from pymongo import MongoClient
from pymongo.errors import (
ConnectionFailure,
OperationFailure,
DuplicateKeyError
)
try:
client = MongoClient('mongodb://localhost:27017/')
db = client.myapp
# 插入重复键
db.users.insert_one({"email": "test@example.com"})
except DuplicateKeyError as e:
print(f"重复键错误: {e}")
except OperationFailure as e:
print(f"操作失败: {e}")
except ConnectionFailure as e:
print(f"连接失败: {e}")
except Exception as e:
print(f"未知错误: {e}")
5.2 Node.js错误处理
javascript
const mongoose = require('mongoose');
mongoose.connect('mongodb://localhost:27017/myapp');
// 连接错误
mongoose.connection.on('error', (err) => {
console.error('MongoDB连接错误:', err);
});
// 模型方法错误处理
async function safeFind() {
try {
const user = await User.findOne({ username: 'test' });
if (!user) {
throw new Error('用户不存在');
}
return user;
} catch (error) {
console.error('查询错误:', error.message);
throw error;
}
}
// 验证错误
const user = new User({ username: 'ab' }); // 太短
const error = user.validateSync();
if (error) {
console.error('验证错误:', error.errors);
}
六、总结
📊 本篇总结:
✅ 掌握内容:
- Python pymongo基础连接
- Python CRUD和聚合操作
- Node.js mongoose使用
- Schema定义和模型
- 连接池配置
- 实战博客系统
- 错误处理
作者 :刘~浪地球
更新时间 :2026-05-11
本文声明:原创不易,转载需授权!