如何在Mongoose模型数组中为每个元素添加课时合计字段
解决Mongoose数组元素单独计算合计字段的问题
核心问题原因
你之前用virtual得到所有科目总合计,是因为把virtual定义在了父文档级别,它会遍历整个数组求和。要实现每个元素单独的Tot,需要把virtual定义在数组的子文档Schema上。
方法一:子文档Schema定义Virtual(推荐)
这是最优雅的方式,让每个子文档自己管理合计字段:
// 1. 定义子文档的Schema const UniversitySubjectSchema = new mongoose.Schema({ name: { type: String }, level: { type: String }, lecture_hours: { type: Number, default: 0 }, labs_hours: { type: Number, default: 0 } }); // 2. 给子文档添加virtual字段Tot UniversitySubjectSchema.virtual('Tot').get(function() { // this指向当前子文档对象,只计算自身的lecture和labs小时和 return this.lecture_hours + this.labs_hours; }); // 3. 配置让virtual字段在转JSON/普通对象时自动包含 UniversitySubjectSchema.set('toJSON', { virtuals: true }); UniversitySubjectSchema.set('toObject', { virtuals: true }); // 4. 父模型中使用该子文档Schema const YourModel = mongoose.model('YourModel', new mongoose.Schema({ university_subject_list: [UniversitySubjectSchema], // 其他业务字段... }));
使用时,查询出来的每个university_subject_list元素都会自动带上Tot字段,且值为当前元素的小时总和。
方法二:聚合查询时动态计算
如果不想修改模型结构,可以在查询阶段用MongoDB聚合管道的$map操作符,动态给每个数组元素添加Tot:
YourModel.aggregate([ { $project: { // 遍历数组,给每个元素计算Tot university_subject_list: { $map: { input: "$university_subject_list", as: "subject", in: { name: "$$subject.name", level: "$$subject.level", lecture_hours: "$$subject.lecture_hours", labs_hours: "$$subject.labs_hours", _id: "$$subject._id", Tot: { $add: ["$$subject.lecture_hours", "$$subject.labs_hours"] } } } }, // 保留其他需要的字段,比如_id、其他业务字段 _id: 1 } } ]).exec((err, results) => { // 处理查询结果,每个subject都有单独的Tot });
方法三:Post查询钩子手动添加
这种方式适合临时需求,在查询完成后手动给每个元素赋值:
// 给find查询添加后置钩子 YourModel.post('find', function(docs) { docs.forEach(doc => { doc.university_subject_list.forEach(subject => { subject.Tot = subject.lecture_hours + subject.labs_hours; }); }); }); // 给findOne查询添加后置钩子 YourModel.post('findOne', function(doc) { if (doc?.university_subject_list) { doc.university_subject_list.forEach(subject => { subject.Tot = subject.lecture_hours + subject.labs_hours; }); } });
内容的提问来源于stack exchange,提问作者Genti
相关产品推荐
相关产品推荐

