mongodb & mongoose 保存文档时如何自动创建新集合
错误诱因
你出现该报错的核心原因是Mongoose的集合绑定在Model层面,而非单个文档实例层面,你的用法存在两个问题:
new Model(文档数据, 配置)的第二个参数并不是用来指定集合名的,传入非法的{collection:xxx}配置会打断文档实例的初始化流程,导致Mongoose没有自动为文档生成_id字段,进而抛出document must have an _id before saving错误。- 你在
models/hometask.js中直接导出了绑定固定集合hometask的Model,本来就不支持动态切换集合。
修复方案
第一步:修改models/hometask.js,复用Schema
不要直接导出绑定固定集合的Model,改为导出通用的Schema,用于后续动态创建不同集合的Model:
const mongoose = require('mongoose'); const { Schema } = mongoose; const RecordSchema = new Schema({ name: { type: String, required: true }, description: { type: String, required: true }, importance: { type: Boolean, required: true }, group: { type: String, required: true } }); // 导出Schema而非固定集合的Model module.exports = RecordSchema;
第二步:修改api/hometask.js,动态创建对应集合的Model
每次请求拿到group参数后,先判断该分组对应的Model是否已经被Mongoose缓存,没有的话再基于通用Schema创建,避免重复注册报错:
const express = require('express'); const router = express.Router(); const mongoose = require('mongoose'); // 引入通用Schema const RecordSchema = require('../models/hometask'); router.post('/', async (req, res) => { const request = req.body; const groupName = request.group; // 校验group参数合法性,避免非法集合名风险 if (!groupName || typeof groupName !== 'string' || /[.$\0]/.test(groupName)) { return res.status(400).json({status: 'fail', msg: '非法的分组参数'}); } // 优先取缓存的Model,没有则创建新的(绑定对应group的集合) let RecordModel; if (mongoose.models[groupName]) { RecordModel = mongoose.models[groupName]; } else { // 第三个参数强制指定集合名,避免Mongoose自动转复数 RecordModel = mongoose.model(groupName, RecordSchema, groupName); } // 用对应集合的Model创建文档实例 const record = new RecordModel(request); try { await record.save(); res.json({ status: 'success' }); } catch (err) { console.log(err); res.status(500).json({status: 'fail', msg: '保存失败'}); } }) module.exports = router;
额外说明
修复后Mongoose会自动为不存在的集合创建对应的集合,和pymongo的行为一致,不需要额外配置。
内容的提问来源于stack exchange,提问作者JoshJohnson
相关产品推荐
相关产品推荐

