如何阻止Mongoose为模板Schema自动生成空数据库集合
问题根因
额外生成空quizzes集合的核心原因是你调用了mongoose.model('quiz', quizzes)将quizzes结构注册为独立数据模型:只要执行了mongoose.model()注册操作,Mongoose就会为该模型绑定独立的同名集合,哪怕你从未向该集合写入任何数据,连接数据库时也会自动创建这个空集合。
另外你当前对game_content字段的定义存在语法错误:enum校验仅支持对字符串、数字等原始值做可选范围限制,传入Schema对象不会起到子文档结构校验的作用,也无法实现不同游戏类型对应不同内容结构的需求。
修正方案
1. 子文档结构不要注册为独立模型
如果你只需要quizzes、puzzles作为嵌套在Games文档里的子结构,不需要单独存储这两类数据,就不要给对应的Schema调用mongoose.model(),仅导出Schema本身即可:
// quizzes.js 仅定义子文档Schema,不注册独立模型 const mongoose = require('mongoose'); const quizzesSchema = new mongoose.Schema({ question: { type: String }, answer: { type: String } }) module.exports = quizzesSchema;
puzzles结构同理,只定义Schema导出,不要注册模型。
2. 使用Mongoose子文档判别器(Discriminator)实现多态内容
Mongoose官方提供了判别器能力来支持同一字段下匹配不同结构的子文档,完美适配你多游戏类型的场景,修正后的Games Schema定义如下:
const mongoose = require('mongoose'); const quizzesSchema = require('./quizzes'); // 定义puzzles子文档Schema,同样不注册独立模型 const puzzlesSchema = new mongoose.Schema({ // 按需补充puzzle类型的专属字段 puzzle_tip: String, correct_answer: String }) const Games = new mongoose.Schema({ // 所有游戏通用字段 game_name: String, date_created: { type: Date, default: Date.now }, game_type: { type: String, enum: ['quizzes', 'puzzles', 'multiplayer'], required: true } }) // 为game_content字段配置多态子文档,以game_type作为判别键 const gameContent = Games.path( 'game_content', new mongoose.Schema({}, { discriminatorKey: 'game_type', _id: false }) ); // 绑定不同游戏类型对应的子文档Schema gameContent.discriminator('quizzes', quizzesSchema); gameContent.discriminator('puzzles', puzzlesSchema); module.exports = mongoose.model('games', Games);
3. 调整新建游戏的写入逻辑
现在不需要实例化独立的Quiz模型,直接传入对应游戏类型的内容即可,Mongoose会自动根据game_type匹配对应的Schema做字段校验:
const game = new Game({ game_name: "game 1", game_type: "quizzes", game_content: { question: "this is question 1", answer: "this is answer 1" } }) await game.save();
补充说明
- 移除子文档Schema的
mongoose.model()注册语句后,Mongoose不会再生成多余的空集合,所有游戏数据都会统一存在games集合中。 - 子文档判别器会自动做结构校验,如果quizzes类型的游戏内容缺了question/answer字段,或者puzzles类型传了不属于它的字段,写入时Mongoose会直接抛出校验错误,比原来存纯Object类型的可靠性高很多。
- 后续新增multiplayer类型的游戏内容时,只需要定义对应结构的Schema,再调用
gameContent.discriminator('multiplayer', 对应Schema)即可完成扩展,不需要修改原有核心逻辑。
内容的提问来源于stack exchange,提问作者mallorc
相关产品推荐
相关产品推荐

