多技术领域选择题存储:MongoDB vs RDBMS及MongoDB存储检索方法
选择题数据存储:MongoDB vs RDBMS方案对比及MongoDB实践
一、哪种方案更优?
你的核心需求是按特定技术/能力维度检索题目,数据量从数百到数千级,两种方案都能支撑,但差异主要在灵活性和维护成本:
RDBMS(如MySQL、PostgreSQL)
- 优势:数据结构规整,适合属性固定、要求严格数据一致性的场景。如果你的题目属性(题干、选项、答案、技能标签)不会频繁变更,用RDBMS能保证数据严谨性,关联查询(比如统计某技能下的题目数量)效率稳定。
- 劣势:后续要给题目加新属性(比如难度分级、出题年份)时,必须修改表结构,流程繁琐。技能标签多对多关联需要建中间表,查询时要做JOIN,虽然数据量不大时影响有限,但灵活性远不如MongoDB。
MongoDB
- 优势:文档型存储天然适配半结构化数据,每道题可直接作为一个独立文档存储,技能标签用数组字段嵌入即可,无需额外中间表。后续加新属性直接在文档里补充,不用改整体结构,灵活性拉满。按技能标签检索的语法简洁,数千级数据量完全无压力。
- 劣势:如果需要复杂的跨维度聚合统计(比如跨多个技能的答题数据交叉分析),MongoDB的聚合查询学习成本比SQL高一点,但你的需求里这类场景应该不多。
结论:如果题目属性可能灵活调整,或者更看重按技能检索的便捷性,选MongoDB更合适;如果数据结构完全固定,且依赖强一致性和复杂SQL查询,RDBMS更稳妥。从你的需求(按技能展示题目、数据量增长到数千)来看,MongoDB的灵活性更匹配。
二、MongoDB的存储与检索实现
1. 数据结构设计
将每道题作为独立文档,核心字段参考如下:
{ "_id": ObjectId("60d21b4667d0d8992e610c85"), // MongoDB自动生成的主键 "question_title": "以下哪个不是Python的内置数据类型?", // 题干 "options": [ {"label": "A", "content": "list"}, {"label": "B", "content": "tuple"}, {"label": "C", "content": "map"}, {"label": "D", "content": "dict"} ], // 选项列表 "correct_answer": "C", // 正确答案 "skills": ["Python基础", "数据类型"], // 关联的技能/能力维度,用数组存储 "difficulty": "简单", // 可选:后续可扩展的属性 "user_choices": [ // 可选:存储用户答题记录,也可拆分到独立集合 {"user_id": "user123", "choice": "C", "submit_time": ISODate("2024-05-20T10:00:00Z")}, {"user_id": "user456", "choice": "D", "submit_time": ISODate("2024-05-20T10:15:00Z")} ] }
- 关键设计:用
skills数组存储关联技能标签,这是实现按技能检索的核心。 - 优化建议:如果用户答题记录较多,建议把
user_choices拆成独立集合(比如命名为user_question_answers),结构为{"user_id": "...", "question_id": "...", "choice": "...", "submit_time": "..."},避免单文档过大,也方便单独查询用户答题记录。
2. 检索操作
(1)查询某技能下的所有题目
比如查找关联"Python基础"的题目:
// MongoDB Shell命令 db.questions.find({ "skills": "Python基础" })
如果要同时匹配多个技能(如既属于Python基础又属于数据类型):
db.questions.find({ "skills": {$all: ["Python基础", "数据类型"]} })
(2)统计某技能下的题目数量
db.questions.countDocuments({ "skills": "Python基础" })
(3)查询某用户在某技能下的答题记录
若用户答题记录存在独立集合,可先查技能对应的题目ID,再关联用户记录:
const questionIds = db.questions.find({skills: "Python基础"}, {_id: 1}).map(doc => doc._id); db.user_question_answers.find({ user_id: "user123", question_id: {$in: questionIds} })
也可用聚合管道直接关联查询:
db.user_question_answers.aggregate([ {$match: {user_id: "user123"}}, {$lookup: { from: "questions", localField: "question_id", foreignField: "_id", as: "question_info" }}, {$match: {"question_info.skills": "Python基础"}}, {$project: {user_id: 1, choice: 1, submit_time: 1, question_title: "$question_info.question_title"}} ])
3. 性能优化
- 给
skills字段建索引,加快检索速度:db.questions.createIndex({skills: 1}) - 若用户答题记录较多,给
user_id和question_id建复合索引:db.user_question_answers.createIndex({user_id: 1, question_id: 1})
内容的提问来源于stack exchange,提问作者Onlydocs
相关产品推荐
相关产品推荐

