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

MongoDB不存在对应条目时如何新建?基于Mongoose实现咨询

现有代码存在的问题

  • 你使用的Year.find()返回的是匹配结果的数组,哪怕没有匹配到任何文档,返回的也是空数组[],而空数组在JavaScript中布尔判断为true,所以你写的if(found)永远成立,不会走到新建条目的分支里。如果要做单条查询应该用findOne()而不是find()。
  • 回调写法可读性较低,也不容易做异常全链路捕获,建议使用async/await语法处理异步逻辑。
  • 没有对save操作的错误做捕获,容易出现静默失败的问题。

推荐最优方案:使用upsert原子操作

Mongoose内置的upsert功能完全适配你的需求,是数据库层面的原子操作,比先查再写的逻辑性能更高,还能避免并发请求下重复创建条目的问题,不需要自己手写查询判断逻辑:

// 用户录入2022年数据时直接执行即可
await Year.updateOne(
  { year: 2022 }, // 匹配条件
  { 
    $set: {
      // 这里直接放用户录入的需要更新的字段即可
      "sheet1.f_jan_acc": 5,
      "sheet1.gi_jan_acc": 2,
      // 其余字段按需传入
    }
  },
  { upsert: true } // 开启upsert,匹配不到就自动插入新文档
)

如果你的场景需要拿到更新/插入后的完整文档,可以使用findOneAndUpdate:

const yearDoc = await Year.findOneAndUpdate(
  { year: 2022 },
  { $set: {/* 要更新的字段 */} },
  { 
    upsert: true,
    new: true, // 返回更新后的新文档,默认返回更新前的旧文档
    setDefaultsOnInsert: true // 插入新文档时自动应用schema中定义的默认值(如果有配置默认值的话)
  }
)

如果你坚持要使用先查后写的逻辑,优化写法如下

try {
  // 单条查询用findOne
  const foundYear = await Year.findOne({ year: 2022 })
  if (!foundYear) {
    // 不存在则新建
    await Year.create({ year: 2022 })
  }
  // 后续执行更新逻辑
} catch (err) {
  console.error('操作失败:', err)
}

额外优化建议

给year字段加上唯一索引,避免出现同年份重复条目的问题,修改schema如下:

const yearSchema = new mongoose.Schema({
  year: {
    type: Number,
    unique: true // 加唯一索引
  },
  sheet1: {
    f_jan_acc: Number,
    gi_jan_acc: Number,
    mi_jan_acc: Number,
    ni_jan_acc: Number,
    tot_jan_acc: Number,
  }
})

加了唯一索引后,即使出现并发请求也不会插入重复的year文档,数据一致性更有保障。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.26 15:39:04