全局配置与最佳实践
全局配置与最佳实践
Mongoose 的全局配置允许开发者统一管理连接行为、模型定义和查询逻辑。合理使用这些配置能显著提升代码可维护性,避免重复设置。以下从连接配置、模型选项到插件机制展开说明核心配置项及其应用场景。
连接池与性能调优
连接池配置直接影响数据库操作的吞吐量。默认情况下Mongoose创建5个连接,高并发场景需要调整:
mongoose.connect('mongodb://localhost:27017/mydb', {
poolSize: 20, // 最大连接数
socketTimeoutMS: 45000, // socket超时
connectTimeoutMS: 30000, // 连接超时
serverSelectionTimeoutMS: 5000 // 服务器选择超时
});
关键参数说明:
maxPoolSize
:替换旧版poolSize参数,建议设置为应用线程数的1-2倍waitQueueTimeoutMS
:连接请求在队列中的最长等待时间heartbeatFrequencyMS
:心跳检测间隔,默认10秒
生产环境推荐配合retry机制:
const options = {
autoIndex: false, // 生产环境禁用自动索引
retryWrites: true,
retryReads: true,
retryAttempts: 3,
retryDelay: 1000
};
Schema级别配置
通过Schema定义可以预设模型行为,避免在每个查询中重复声明:
const userSchema = new mongoose.Schema({
username: String,
email: String
}, {
timestamps: true, // 自动添加createdAt/updatedAt
minimize: false, // 保留空对象
toJSON: {
virtuals: true,
transform: (doc, ret) => {
ret.id = ret._id;
delete ret._id;
delete ret.__v;
return ret;
}
},
optimisticConcurrency: true // 启用乐观锁
});
特别有用的配置项:
strictQuery
: 控制查询时的字段过滤,建议设为trueid
: 是否将_id映射为id,默认trueversionKey
: 修改__v字段名或禁用版本控制
全局插件注册
通过全局插件可统一扩展所有模型功能。典型场景如自动设置更新时间戳:
mongoose.plugin((schema) => {
schema.pre('save', function(next) {
this.updatedAt = new Date();
next();
});
schema.post('find', function(docs) {
console.log(`查询返回 ${docs.length} 条记录`);
});
});
实际项目常用插件组合:
mongoose-autopopulate
自动填充引用字段mongoose-lean-virtuals
为lean查询添加虚拟字段mongoose-paginate-v2
分页插件
// 分页插件配置示例
mongoose.plugin(require('mongoose-paginate-v2'), {
limit: 10,
customLabels: {
totalDocs: 'itemCount',
docs: 'itemsList'
}
});
查询中间件优化
全局查询钩子能实现AOP风格的逻辑复用:
mongoose.set('debug', process.env.NODE_ENV === 'development');
// 所有查询添加基础过滤
mongoose.plugin((schema) => {
schema.pre(/^find/, function() {
if (!this.getFilter().isDeleted) {
this.where({ isDeleted: false });
}
});
});
// 自动转换ID查询
mongoose.plugin((schema) => {
schema.pre('find', function() {
const { _id } = this.getQuery();
if (_id && typeof _id === 'string') {
this.where({ _id: new mongoose.Types.ObjectId(_id) });
}
});
});
多租户处理策略
在SaaS应用中,全局配置可简化租户隔离:
// 动态数据库连接
const tenantConnections = {};
function getTenantConnection(tenantId) {
if (!tenantConnections[tenantId]) {
tenantConnections[tenantId] = mongoose.createConnection(
`mongodb://localhost/${tenantId}`,
{ useNewUrlParser: true }
);
}
return tenantConnections[tenantId];
}
// 模型注册中间件
mongoose.plugin((schema) => {
schema.statics.byTenant = function(tenantId) {
const conn = getTenantConnection(tenantId);
return conn.model(this.modelName, this.schema);
};
});
// 使用示例
const Product = mongoose.model('Product', productSchema);
const tenantAProducts = Product.byTenant('tenantA').find();
性能监控集成
通过全局配置集成监控工具:
const statsDClient = require('hot-shots');
mongoose.plugin((schema) => {
const metrics = new statsDClient();
schema.post('save', function(doc) {
metrics.increment('mongoose.save_operations');
});
schema.post('find', function(docs) {
metrics.timing('mongoose.query_time', this._mongooseOptions.executionTime);
});
});
结合APM工具实现更细粒度监控:
const apm = require('elastic-apm-node');
mongoose.set('debug', function(collectionName, methodName, ...methodArgs) {
const span = apm.startSpan(`MongoDB ${collectionName}.${methodName}`);
// ...执行逻辑
span?.end();
});
类型转换与校验
全局配置自定义类型处理:
// 自定义Decimal128转换
mongoose.Schema.Types.Decimal128.set('toJSON', {
transform: (val) => val ? parseFloat(val.toString()) : null
});
// 全局验证器
mongoose.plugin((schema) => {
schema.pre('validate', function(next) {
if (this.email && !/.+@.+\..+/.test(this.email)) {
this.invalidate('email', 'Invalid email format');
}
next();
});
});
// 枚举类型增强
mongoose.Schema.Types.String.set('validate', {
validator: function(val) {
if (this.enumValues && !this.enumValues.includes(val)) {
return false;
}
return true;
},
message: props => `${props.value} 不是有效枚举值`
});
多语言支持方案
通过全局插件实现模型多语言:
mongoose.plugin((schema) => {
const languages = ['en', 'zh', 'ja'];
languages.forEach(lang => {
schema.add({
[`name_${lang}`]: String,
[`description_${lang}`]: String
});
});
schema.methods.getLocalized = function(field, lang = 'en') {
return this[`${field}_${lang}`] || this[field];
};
});
// 使用示例
const productSchema = new mongoose.Schema({ baseName: String });
const Product = mongoose.model('Product', productSchema);
const p = new Product({
baseName: 'Default',
name_zh: '默认名称',
name_ja: 'デフォルト'
});
console.log(p.getLocalized('name', 'zh')); // 输出: 默认名称
缓存策略实现
全局查询缓存示例:
const cache = new Map();
mongoose.plugin((schema) => {
schema.statics.cachedFind = async function(query, ttl = 60) {
const key = JSON.stringify({
model: this.modelName,
query
});
if (cache.has(key)) {
return cache.get(key);
}
const result = await this.find(query);
cache.set(key, result);
setTimeout(() => cache.delete(key), ttl * 1000);
return result;
};
});
// 使用示例
const User = mongoose.model('User');
const users = await User.cachedFind({ active: true }, 300);
安全防护措施
全局安全相关配置:
// 防止查询注入
mongoose.set('sanitizeFilter', true);
mongoose.set('sanitizeProjection', true);
// 字段级加密
const encryptedFields = require('mongoose-encrypted-field');
mongoose.plugin(encryptedFields, {
secret: process.env.ENCRYPTION_KEY,
fields: ['creditCard', 'ssn']
});
// 审计日志
mongoose.plugin((schema) => {
schema.add({
createdBy: mongoose.Schema.Types.ObjectId,
updatedBy: mongoose.Schema.Types.ObjectId
});
schema.pre('save', function() {
if (this.isNew) {
this.createdBy = currentUser;
}
this.updatedBy = currentUser;
});
});
本站部分内容来自互联网,一切版权均归源网站或源作者所有。
如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn
上一篇:多数据库连接管理
下一篇:Schema的定义与结构