You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在MongoDB(Mongoose)中更新并保存面试数组对象

问题背景与需求

需求:保存面试数组对象,实现第1轮面试安排及反馈完成后保存该轮次数据,后续轮次同理。interview数组的每个元素包含两个子对象:

  • schedule:用于存储面试轮次的安排信息
  • feedback:用于收集对应轮次的面试反馈

提供的Mongoose Schema如下:

const mongoose = require('mongoose');
const mongoosePaginate = require('mongoose-paginate-v2');
const { Schema } = mongoose;

const InterviewSchema = new Schema(
  {
    firstName: {
      type: String,
      required: true,
      trim: true,
      maxlength: 30,
    },
    lastName: {
      type: String,
      trim: true,
      maxlength: 30,
    },
    email: {
      type: String,
      required: true,
      trim: true,
    },
    gender: {
      type: String,
      required: true,
    },
    contactNumber: {
      type: Number,
      required: true,
    },
    profile: {
      type: String,
      required: true,
    },
    status: {
      type: String,
    },
    // 面试轮次数组
    interview: [
      {
        schedule: {
          interviewerName: {
            type: String,
            trim: true,
          },
          date: {
            type: Date,
            default: Date.now,
          },
          mode: {
            type: String,
          },
          meeting: {
            link: {
              type: String,
              trim: true,
            },
            platform: {
              type: String,
              trim: true,
            },
          },
          round: {
            count: {
              type: Number,
              default: 1,
            },
            type: {
              type: String,
              default: 'hr',
            },
          },
        },
        feedback: {
          technical: {
            type: Number,
            required: true,
            min: 1,
            max: 5,
          },
          logical: {
            type: Number,
            required: true,
            min: 1,
            max: 5,
          },
          communication: {
            type: Number,
            required: true,
            min: 1,
            max: 5,
          },
          comment: {
            type: String,
            min: 10,
            max: 200,
            default: '',
          },
          interviewStatus: {
            type: String,
          },
          recommendation: {
            type: String,
            default: '',
          },
        },
      },
    ],
  },
  {
    timestamps: true,
  },
);

InterviewSchema.plugin(mongoosePaginate);
const InterviewProcess = mongoose.model('interviewprocess', InterviewSchema);
module.exports = InterviewProcess;

遇到的问题

已完成数组对象中schedule轮次与反馈的更新,但无法保存数据,旧的安排会被覆盖。编写的updateSchedule代码如下:

static async updateSchedule(request, h) {
    try {
      const payload = request.payload.interview[0];
      const params = request.query._id;
      const interviewSchedule =
        await interviewProcessService.findByinterviewProcessId(params);
      if (!interviewSchedule) {
        return h.response({
          statusCode: MESSAGE.STATUS.ERROR,
          message: MESSAGE.ID_NOT_EXIST,
        });
      }

      let mode,
        meeting,
        round,
        technical,
        logical,
        communication,
        comment,
        interviewStatus,
        recommendation,
        interviewerName;
      if (payload.schedule) {
        interviewerName = _.get(payload.schedule, 'interviewerName');
        mode = _.get(payload.schedule, 'mode');
        meeting = _.get(payload.schedule, 'meeting');
        round = _.get(payload.schedule, 'round') || {};
      }

      if (payload.feedback) {
        mode = _.get(interviewSchedule.interview[0].schedule, 'mode');
        meeting = _.get(interviewSchedule.interview[0].schedule, 'meeting');
        round = _.get(interviewSchedule.interview[0].schedule, 'round') || {};
        interviewerName = _.get(
          interviewSchedule.interview[0].schedule,
          'interviewerName',
        );

        technical = _.get(payload.feedback, 'technical');
        logical = _.get(payload.feedback, 'logical');
        communication = _.get(payload.feedback, 'communication');
        comment = _.get(payload.feedback, 'comment');
        interviewStatus = _.get(payload.feedback, 'interviewStatus');
        recommendation = _.get(payload.feedback, 'recommendation');
      }

      const result = await interviewProcessService.update(params, {
        interview: {
          schedule: {
            interviewerName,
            mode,
            meeting,
            round,
          },
          feedback: {
            technical,
            logical,
            communication,
            comment,
            interviewStatus,
            recommendation,
          },
        },
      });

      return h.response({
        result,
        statusCode: MESSAGE.STATUS.SUCCESS,
        message: MESSAGE.ROUTES.SCHEDULE_UPDATE.MESSAGE,
      });
    } catch (error) {
      return ErrorHandler.error(error);
    }
  }

期望实现:调用GET方法时,能获取所有带有反馈的面试轮次信息。


问题原因与修复方案

核心问题

当前代码直接替换了整个interview数组,而非追加新轮次或更新指定轮次,导致旧数据被覆盖;同时代码仅处理数组第一个元素,无法支持多轮次的新增与更新。

修复步骤

1. 区分「新增轮次」与「更新已有轮次」

根据传入的round.count判断操作类型:

  • 新增轮次:使用MongoDB的$push操作符向interview数组追加元素
  • 更新轮次:使用$set配合数组索引定位,精准更新指定轮次的内容

2. 重构updateSchedule代码

static async updateSchedule(request, h) {
  try {
    const payload = request.payload.interview[0];
    const params = request.query._id;
    const interviewRecord = await interviewProcessService.findByinterviewProcessId(params);
    
    if (!interviewRecord) {
      return h.response({
        statusCode: MESSAGE.STATUS.ERROR,
        message: MESSAGE.ID_NOT_EXIST,
      });
    }

    let updateQuery = {};
    // 获取目标轮次编号,默认1
    const targetRoundCount = payload.schedule?.round?.count || 1;

    // 检查是否存在该轮次
    const existingRoundIndex = interviewRecord.interview.findIndex(
      item => item.schedule.round.count === targetRoundCount
    );

    if (existingRoundIndex === -1) {
      // 新增轮次:用$push追加到数组
      updateQuery.$push = {
        interview: {
          schedule: {
            interviewerName: payload.schedule?.interviewerName,
            mode: payload.schedule?.mode,
            meeting: payload.schedule?.meeting,
            round: payload.schedule?.round || { count: 1, type: 'hr' },
            date: payload.schedule?.date || new Date()
          },
          feedback: payload.feedback ? {
            technical: payload.feedback.technical,
            logical: payload.feedback.logical,
            communication: payload.feedback.communication,
            comment: payload.feedback.comment || '',
            interviewStatus: payload.feedback.interviewStatus,
            recommendation: payload.feedback.recommendation || ''
          } : {
            // 反馈为必填项,此处可根据需求调整默认值或抛出错误
            technical: 1,
            logical: 1,
            communication: 1,
            comment: '',
            interviewStatus: 'pending',
            recommendation: ''
          }
        }
      };
    } else {
      // 更新已有轮次:合并原有数据与新数据,避免丢失未修改字段
      updateQuery.$set = {};
      if (payload.schedule) {
        updateQuery.$set[`interview.${existingRoundIndex}.schedule`] = {
          ...interviewRecord.interview[existingRoundIndex].schedule,
          ...payload.schedule
        };
      }
      if (payload.feedback) {
        updateQuery.$set[`interview.${existingRoundIndex}.feedback`] = {
          ...interviewRecord.interview[existingRoundIndex].feedback,
          ...payload.feedback
        };
      }
    }

    const result = await interviewProcessService.update(params, updateQuery);

    return h.response({
      result,
      statusCode: MESSAGE.STATUS.SUCCESS,
      message: MESSAGE.ROUTES.SCHEDULE_UPDATE.MESSAGE,
    });
  } catch (error) {
    return ErrorHandler.error(error);
  }
}

3. 优化GET接口返回结果

如果需要仅返回带有反馈的轮次,可在查询时添加过滤条件:

// 示例:查询所有包含有效反馈的面试记录
const records = await InterviewProcess.find({
  'interview.feedback.technical': { $exists: true }
}).exec();

若需返回所有轮次(包括未填写反馈的),直接返回interview数组即可。

关键说明

  • 使用$push而非直接赋值数组,彻底避免旧数据被覆盖
  • 通过findIndex定位已有轮次,实现精准更新
  • 用扩展运算符...合并新旧数据,保留未修改的字段
  • 同时支持「新增轮次」和「更新轮次」两种场景,满足多轮面试流程需求

内容的提问来源于stack exchange,提问作者RK Varun

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 21:25:16