Node.js Mongoose:查询文档,不存在则保存的实现疑问
嘿,刚上手Mongoose碰到这种问题太正常了!我来给你拆解一下怎么实现「查询不存在就保存」的需求,尤其是你这种把问题存在数组对象里的场景。
解决方案:针对数组对象的「不存在则保存」实现
首先得明确你的数据结构,我先假设你是把多个问题嵌套在一个主文档(比如Survey问卷)的数组里,先给你搭好基础的Schema:
// 子文档:单个问题的Schema const questionSchema = new mongoose.Schema({ global_id: { type: String, required: true, unique: true }, // 用global_id做唯一标识 question: String, type: String, answers: [String] // 其他自定义字段按需添加 }); // 主文档:包含问题数组的Schema,比如Survey const surveySchema = new mongoose.Schema({ surveyName: { type: String, required: true }, // 比如问卷名称,用来定位主文档 questions: [questionSchema] }); // 创建模型 const Survey = mongoose.model('Survey', surveySchema);
场景1:主文档存在则追加新问题,不存在则创建文档并添加问题
如果你的需求是:找到指定的问卷(比如按surveyName),如果问卷里没有某个global_id的问题,就把它加进去;如果问卷本身不存在,就新建问卷并添加这个问题。
方式1:逐个处理问题(适合新手,直观)
const targetSurveyName = '用户反馈问卷'; const questions = [/* 你的问题数组 */]; // 遍历每个问题,检查并添加 for (const question of questions) { await Survey.findOneAndUpdate( // 查询条件:找到指定问卷,且问卷的questions数组里没有该global_id的问题 { surveyName: targetSurveyName, 'questions.global_id': { $ne: question.global_id } }, // 更新操作:把问题推送到数组里 { $push: { questions: question } }, // 配置项:upsert为true表示如果找不到符合条件的文档,就新建一个 { upsert: true } ); }
方式2:批量处理(效率更高,适合多问题场景)
如果问题数量较多,多次查询数据库效率低,可以用bulkWrite批量操作:
const targetSurveyName = '用户反馈问卷'; const questions = [/* 你的问题数组 */]; // 构造批量操作数组 const batchOperations = questions.map(q => ({ updateOne: { filter: { surveyName: targetSurveyName, 'questions.global_id': { $ne: q.global_id } }, update: { $push: { questions: q } }, upsert: true } })); // 执行批量操作 await Survey.bulkWrite(batchOperations);
场景2:每个问题是独立的文档
如果你的需求是把每个问题作为单独的文档存储(而不是嵌套在数组里),那就更简单了,直接针对Question模型用findOneAndUpdate的upsert特性:
// 先创建Question模型 const Question = mongoose.model('Question', questionSchema); const questions = [/* 你的问题数组 */]; for (const question of questions) { await Question.findOneAndUpdate( // 按global_id查找问题 { global_id: question.global_id }, // 如果找到就更新(这里直接传入整个question对象,会覆盖原有字段;如果只想新增字段可以用$set) question, // 配置项:upsert=true表示不存在就创建,new=true表示返回更新/创建后的文档 { upsert: true, new: true } ); }
关键注意事项
- 唯一性保障:一定要给
global_id加上unique: true约束,这样MongoDB会在数据库层面保证global_id不重复,避免并发情况下出现重复添加的问题。如果是嵌套数组的场景,还可以给主文档创建复合索引,确保同一个问卷里的问题global_id唯一:
// 给Survey模型创建复合索引:同一个surveyName下,questions的global_id不能重复 surveySchema.index({ surveyName: 1, 'questions.global_id': 1 }, { unique: true });
- 并发问题:如果有多个请求同时添加相同
global_id的问题,光靠代码层面的判断可能会有漏网之鱼,数据库层面的唯一索引是最可靠的保障。
这样应该就能完美满足你的需求啦,要是还有细节问题可以再补充~
内容的提问来源于stack exchange,提问作者Camille Sébastien Niessen
相关产品推荐
相关产品推荐

