推荐方案:关系存储在 Article 表中
// articles 集合 { _id: ObjectId("..."), title: "文章标题", content: "文章内容", categoryId: ObjectId("category_id"), // 引用分类ID tagIds: [ ObjectId("tag_id_1"), ObjectId("tag_id_2"), ObjectId("tag_id_3") ], // 引用标签ID数组 createdAt: ISODate("..."), updatedAt: ISODate("...") } // categories 集合 { _id: ObjectId("..."), name: "技术文章", slug: "tech", description: "技术相关文章", articleCount: 15, // 该分类下的文章数量 createdAt: ISODate("...") } // tags 集合 { _id: ObjectId("..."), name: "JavaScript", slug: "javascript", color: "#f7df1e", articleCount: 8, // 使用该标签的文章数量 createdAt: ISODate("...") }
为什么选择这种方案?
优点:
-
查询性能高:获取文章时直接拿到所有关系ID
-
结构简单:不需要维护额外的关系表
-
符合 MongoDB 设计哲学:文档数据库适合嵌入/引用关系
-
易于维护:添加/删除标签只需更新文章的 tagIds 数组
查询示例:
获取文章及其分类和标签信息:
// 使用聚合查询 db.articles.aggregate([ { $match: { _id: ObjectId("文章ID") } }, { $lookup: { from: "categories", localField: "categoryId", foreignField: "_id", as: "category" } }, { $lookup: { from: "tags", localField: "tagIds", foreignField: "_id", as: "tags" } }, { $project: { title: 1, content: 1, category: { $arrayElemAt: ["$category", 0] }, tags: 1, createdAt: 1 } } ])
获取某个分类下的所有文章:
db.articles.find({ categoryId: ObjectId("分类ID") })
获取包含某个标签的所有文章:
db.articles.find({ tagIds: ObjectId("标签ID") })
为什么不推荐单独的关系表?
在 MongoDB 中创建单独的关系表(如 article_tags)会增加复杂性:
-
额外的查询开销:需要多次查询才能获取完整信息
-
维护复杂:需要同时更新多个集合
-
事务问题:在分布式环境中维护数据一致性更困难
前端处理示例
// 创建文章时 const createArticle = async (articleData) => { const article = { title: articleData.title, content: articleData.content, categoryId: articleData.categoryId, // 分类ID tagIds: articleData.tagIds, // 标签ID数组 createdAt: new Date() } return await api.createArticle(article) } // 获取文章详情时 const getArticleDetail = async (articleId) => { // 可以一次查询获取完整信息,或者分开查询 // 方式1:后端聚合查询返回完整数据 const article = await api.getArticleWithRelations(articleId) // 方式2:分别查询然后组合 const [article, categories, tags] = await Promise.all([ api.getArticle(articleId), api.getCategories(), api.getTags() ]) return { ...article, category: categories.find(c => c._id === article.categoryId), tags: tags.filter(t => article.tagIds.includes(t._id)) } }
索引优化
为了提升查询性能,记得创建索引:
// 在 articles 集合上创建索引 db.articles.createIndex({ categoryId: 1 }) db.articles.createIndex({ tagIds: 1 }) db.articles.createIndex({ createdAt: -1 }) // 在 categories 和 tags 集合上创建索引 db.categories.createIndex({ slug: 1 }, { unique: true }) db.tags.createIndex({ slug: 1 }, { unique: true })
总结:在 MongoDB 中,将关系直接存储在文章表中是最简单、最高效的方案,符合文档数据库的设计理念。