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

MongoDB嵌套结构设计:如何高效获取特定课程的任务列表?

文档结构优化方案

针对单文档因多语言翻译超出MongoDB 16MB限制的问题,同时满足业务需求,推荐拆分独立集合+引用关联的设计方案,具体如下:

1. 拆分核心集合

将Course→Module→Lesson→Topic→Tasks的层级结构拆分为5个独立MongoDB集合,每个集合存储对应层级的数据,通过ObjectId关联父级,同时内置多语言字段解决翻译需求:

courses集合

{
  _id: ObjectId("a..."),
  name: {
    en: "How to cook borscht",
    zh: "如何制作罗宋汤"
  },
  createdAt: ISODate("2024-01-01T00:00:00Z") // 课程元数据
}

modules集合

{
  _id: ObjectId("b..."),
  courseId: ObjectId("a..."), // 关联所属课程
  title: {
    en: "Analyzing the composition",
    zh: "食材成分分析"
  },
  order: 1 // 控制模块排序顺序
}

lessons集合

{
  _id: ObjectId("c..."),
  moduleId: ObjectId("b..."), // 关联所属模块
  title: {
    en: "Selecting the Cabbage",
    zh: "挑选卷心菜"
  },
  order: 1
}

topics集合

{
  _id: ObjectId("d..."),
  lessonId: ObjectId("c..."), // 关联所属课时
  title: {
    en: "White Cabbage",
    zh: "白卷心菜"
  },
  order: 1 // 控制Topic排序,用于定位首个Topic
}

tasks集合

{
  _id: ObjectId("e..."),
  topicId: ObjectId("d..."), // 关联所属主题
  description: {
    en: "White cabbage is a common vegetable crop...",
    zh: "白卷心菜是常见蔬菜作物,属于芸薹属的栽培变种..."
  }
}

user_activities集合(单独存储用户行为)

{
  _id: ObjectId("f..."),
  userId: ObjectId("u..."),
  targetType: "task", // 可选值:course/module/lesson/topic/task
  targetId: ObjectId("e..."),
  action: "completed", // 可选值:completed/viewed
  timestamp: ISODate("2024-01-02T10:30:00Z")
}

2. 核心需求实现方式

(1)/api/courses 返回课程大纲

使用MongoDB聚合查询,通过$lookup关联各级数据,按需组装大纲并返回指定语言内容:

db.courses.aggregate([
  {
    $lookup: {
      from: "modules",
      localField: "_id",
      foreignField: "courseId",
      as: "modules",
      pipeline: [
        { $sort: { order: 1 } },
        {
          $lookup: {
            from: "lessons",
            localField: "_id",
            foreignField: "moduleId",
            as: "lessons",
            pipeline: [
              { $sort: { order: 1 } },
              {
                $lookup: {
                  from: "topics",
                  localField: "_id",
                  foreignField: "lessonId",
                  as: "topics",
                  pipeline: [
                    { $sort: { order: 1 } },
                    {
                      $lookup: {
                        from: "tasks",
                        localField: "_id",
                        foreignField: "topicId",
                        as: "tasks"
                      }
                    }
                  ]
                }
              }
            ]
          }
        }
      ]
    }
  },
  // 过滤返回中文内容
  {
    $project: {
      "name": "$name.zh",
      "modules.title": "$modules.title.zh",
      "modules.lessons.title": "$modules.lessons.title.zh",
      "modules.lessons.topics.title": "$modules.lessons.topics.title.zh",
      "modules.lessons.topics.tasks.description": "$modules.lessons.topics.tasks.description.zh",
      "modules.order": 1,
      "modules.lessons.order": 1,
      "modules.lessons.topics.order": 1
    }
  }
])

(2)获取指定Lesson的首个Topic下所有任务

通过两步查询快速定位目标数据:

// 1. 找到指定Lesson的首个Topic(按order排序)
const firstTopic = await db.topics.findOne(
  { lessonId: ObjectId("指定lesson的_id") },
  { sort: { order: 1 } }
);

// 2. 获取该Topic下的所有任务
const tasks = await db.tasks.find(
  { topicId: firstTopic._id },
  { "description.zh": 1 } // 按需返回对应语言
).toArray();

(3)用户完成行为记录

直接向user_activities集合插入文档即可,查询用户完成情况时,通过userId+targetType+action过滤即可快速获取结果。

3. 性能优化建议

  • 给每个集合的关联字段添加单字段索引:比如modules.courseId、lessons.moduleId、topics.lessonId、tasks.topicId,加速关联查询。
  • 给user_activities添加复合索引:{ userId: 1, targetType: 1, action: 1 },提升用户行为记录的查询效率。
  • 若课程大纲访问频繁,可将组装好的大纲缓存到Redis中,减少MongoDB聚合查询的压力。

4. 方案优势

  • 彻底解决单文档因多语言翻译超出16MB限制的问题,每个文档体积小巧易维护。
  • 查询灵活:可单独查询任意层级的数据,无需加载整个课程文档,性能更优。
  • 扩展性强:后续新增层级或修改内容时,仅需调整对应集合,不影响整体结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.06 02:34:57