Mongoose中如何实现多字段求和并自动更新总事故统计字段
实现方案
方案1:将总事故数持久化存储到数据库(匹配需求推荐)
第一步:调整Schema定义,新增总事故数字段
const mongoose = require('mongoose') const accidentSchema = new mongoose.Schema({ year: { type: Number, required: true }, // 以下为原有5类事故字段,可替换为你的实际字段命名 trafficAccident: { type: Number, default: 0 }, fireAccident: { type: Number, default: 0 }, workSafetyAccident: { type: Number, default: 0 }, chemicalLeakAccident: { type: Number, default: 0 }, otherAccident: { type: Number, default: 0 }, // 新增总事故数字段 totalAccidents: { type: Number, default: 0 } })
第二步:添加save前置钩子,处理新增/全量保存场景
新增文档或者调用save()方法全量更新文档时,会自动触发该钩子计算总和:
accidentSchema.pre('save', function(next) { // this指向当前待保存的文档实例 this.totalAccidents = this.trafficAccident + this.fireAccident + this.workSafetyAccident + this.chemicalLeakAccident + this.otherAccident next() })
第三步:添加更新操作前置钩子,处理部分更新场景
针对updateOne、findOneAndUpdate、updateMany这类不会触发save钩子的更新操作,单独配置计算逻辑:
accidentSchema.pre(['updateOne', 'findOneAndUpdate', 'updateMany'], async function(next) { // 拿到查询条件和待更新的字段 const query = this.getQuery() const updateFields = this.getUpdate() // 查询现有文档的原始值 const originDoc = await this.model.findOne(query) if (!originDoc) return next() // 合并更新值和原始值,计算最新总和 const finalTraffic = updateFields.trafficAccident ?? originDoc.trafficAccident const finalFire = updateFields.fireAccident ?? originDoc.fireAccident const finalWork = updateFields.workSafetyAccident ?? originDoc.workSafetyAccident const finalChemical = updateFields.chemicalLeakAccident ?? originDoc.chemicalLeakAccident const finalOther = updateFields.otherAccident ?? originDoc.otherAccident // 把总事故数加入更新字段 this.set({ totalAccidents: finalTraffic + finalFire + finalWork + finalChemical + finalOther }) next() })
注意:如果你的更新操作用到了
$inc这类MongoDB操作符,需要额外从updateFields.$inc中提取增量值做计算,适配对应更新场景即可。如果用到批量写入bulkWrite,对应添加pre('bulkWrite')钩子即可。
方案2:虚拟字段动态计算(无需存储,查询时自动生成)
如果你的场景不需要把总事故数持久化到数据库,仅在查询返回时需要该字段,可以用Mongoose虚拟字段实现,无需维护更新逻辑:
// 定义虚拟字段,不会写入数据库 accidentSchema.virtual('totalAccidents').get(function() { return this.trafficAccident + this.fireAccident + this.workSafetyAccident + this.chemicalLeakAccident + this.otherAccident }) // 配置Schema,使JSON输出、toObject转换时自动携带虚拟字段 accidentSchema.set('toJSON', { virtuals: true }) accidentSchema.set('toObject', { virtuals: true })
该方案优势是无需维护自动更新逻辑,劣势是不能直接用totalAccidents字段做数据库查询、排序、聚合操作。
内容的提问来源于stack exchange,提问作者Rajan
相关产品推荐
相关产品推荐

