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

MongoDB Upsert Mutation问题:首次提交无法获取新记录ID

问题描述

在MongoDB中通过Upsert Mutation实现文档创建或更新时,出现如下问题:

  • 更新已有文档时,Mutation能正常返回文档ID;
  • 创建新文档时,首次返回的ID为null(在Apollo Sandbox和前端console.log中均是如此),只有后续操作才能获取到ID。

需要实现首次返回时就能拿到新创建文档的ID,用于后续业务操作。

相关配置代码

类型定义(TYPEDEF)

updateHourByEmployeeIdByJobDate(
      jobDate: String
      startTime: String
      endTime: String
      hoursWorked: String
      employee: String
    ): Hour

Resolver 代码

updateHourByEmployeeIdByJobDate: async (
      parent,
      { jobDate, startTime, endTime, hoursWorked, employee },
      context
    ) => {
      // if (context.user) {
      console.log("resolver hours update = ");
      return Hour.findOneAndUpdate(
        { employee, jobDate },
        {
          jobDate,
          startTime,
          endTime,
          hoursWorked,
          employee,
        },
        {
          upsert: true,
        }
      );
      // }
      // throw new AuthenticationError("You need to be logged in!");
    },

Mutation 定义

//UPDATE HOUR RECORD - CREATES DOCUMENT IF IT DOESN'T EXIST OR UPDATES IF IT DOES EXIST VIA THE UPSERT OPTION ON THE RESOLVER

export const UPDATE_HOURS_BYEMPLOYEEID_BYJOBDATE = gql`
  mutation UpdateHourByEmployeeIdByJobDate(
    $jobDate: String
    $startTime: String
    $endTime: String
    $hoursWorked: String
    $employee: String
  ) {
    updateHourByEmployeeIdByJobDate(
      jobDate: $jobDate
      startTime: $startTime
      endTime: $endTime
      hoursWorked: $hoursWorked
      employee: $employee
    ) {
      _id
    }
  }
`;

前端执行代码

const [ mostRecentHourUpdateId, setMostRecentHoursUpdateId ] = useState();

const [updateHours] = useMutation(UPDATE_HOURS_BYEMPLOYEEID_BYJOBDATE, {
  onCompleted: (data) => {
    console.log('mutation result #1 = ', data)
    setMostRecentHoursUpdateId(data?.updateHourByEmployeeIdByJobDate?._id);
    console.log('mutation result #2 = ', mostRecentHourUpdateId)
  },
});

//section update database - this mutation is an upsert...it either updates or creates a record
const handleUpdateDatabase = async (data) => {
  console.log(data);
  
  try {
    // eslint-disable-next-line
    const { data2 } = await updateHours({
      variables: {
        jobDate: moment(data.date).format("MMMM DD YYYY"), //"January 20 2023"
        startTime: `${data.startTime}:00 (MST)`, //"12:00:00 (MST)"
        endTime: `${data.endTime}:00 (MST)`, //"13:00:00 (MST)"
        hoursWorked: data.hours.toString(), //"3.0"
        employee: userId, //"6398fb54494aa98f85992da3"
      },
    });

    console.log('handle update database function = data = ', data2); //fix

  } catch (err) {
    console.error(err);
  }

  singleHoursRefetch();

};

解决方案

问题根源在于MongoDB的findOneAndUpdate方法默认返回更新前的文档:

  • 更新已有文档时,更新前的文档存在,因此能返回包含ID的旧文档;
  • 创建新文档时,更新前无对应文档,因此返回null,导致前端拿到的ID为null。

只需在findOneAndUpdate的配置选项中添加new: true,让方法返回更新或创建后的最新文档即可:

修改后的Resolver代码

updateHourByEmployeeIdByJobDate: async (
      parent,
      { jobDate, startTime, endTime, hoursWorked, employee },
      context
    ) => {
      console.log("resolver hours update = ");
      return Hour.findOneAndUpdate(
        { employee, jobDate },
        {
          jobDate,
          startTime,
          endTime,
          hoursWorked,
          employee,
        },
        {
          upsert: true,
          new: true, // 关键配置:返回操作后的最新文档
        }
      );
    },

另外注意:前端onCompleted中的console.log('mutation result #2')会显示旧值,这是因为setMostRecentHoursUpdateId是异步操作。若要查看更新后的ID,可通过useEffect监听状态变化:

useEffect(() => {
  console.log('最新的文档ID:', mostRecentHourUpdateId);
}, [mostRecentHourUpdateId]);

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 01:10:29