Mongo使用upsert时无法插入完整文档问题排查
问题原因与解决方法
核心错误
你在update参数的$set里只指定了updatedAt字段,MongoDB开启upsert: true时,新插入的文档只会包含过滤条件里的字段加上update语句里设置的字段,你完全没把爬取到的listdate、pr等核心字段加入进去,这就是新文档缺失数据的原因。
另外还有字段名不一致的问题:你的原始对象字段是listid,但代码里过滤条件用的是listing_id,可插入后的文档显示是listingid,这里大概率是代码里的字段名拼写错误,必须统一(要么全用listid,要么全用listing_id),否则后续爬取时会因为匹配不到已有记录而重复插入。
修正后的代码
把爬取到的对象字段也加入到$set里,不管是更新还是插入,都会保留/设置这些字段:
try { // 先统一字段名,这里假设原始对象字段是listid,统一为listing_id(也可以反过来调整) const filter = { "listing_id": obj.listid }; const update = { $set: { // 导入原始对象的所有字段 ...obj, // 统一字段名,避免后续匹配出错 listing_id: obj.listid, // 覆盖/设置更新时间 updatedAt: new Date(), }, }; const options = { upsert: true }; const result1 = await collection.updateOne(filter, update, options); counter = counter + 1; console.log('counter: ', counter); console.log('Upserted document:', result1.upsertedId || filter); } catch (err) { // 别忘了添加错误捕获,方便排查问题 console.error('操作失败:', err); }
补充说明
- 用扩展运算符
...obj可以快速把原始对象的所有字段导入到$set里,不用手动逐个列举; - 必须保证过滤条件的字段名和文档里的字段名完全一致,否则会出现“明明已有记录却重复插入”的问题;
- 如果原始对象里本身就有
updatedAt字段,这里的单独设置会覆盖它,确保更新时间是当前操作的时间。
内容的提问来源于stack exchange,提问作者user1592380
相关产品推荐
相关产品推荐

