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
相关产品推荐
相关产品推荐

