在MongoDB中设计数据库模式的正确方法

本文关键字:方法 模式 数据库 MongoDB | 更新日期: 2023-09-27 18:28:27

在我的应用程序中,将有程序列表,每个程序将包含会话列表作表列表。更简单地说,关系如下:

Programs --> Sessions --> Worksheets

在应用程序的某个时刻,我想以表格形式显示所选prgram的工作表列表,如下所示:

--------------------------------
|Worksheet Name | Session Name |
--------------------------------
|Worksheet 1    | Session 2    |
|---------------|--------------|
|Worksheet 3    | Session 1    |
|---------------|--------------|
|               |              |

我的问题是,我是应该选择嵌入文档,即在prgram中嵌入会话,在会话中嵌入工作表,还是应该选择程序、会话和工作表的单独集合,并使用类似于RDBMS中外键的概念将它们关联起来?

我担心的是,如果我选择单独的集合,那么对于上面的场景,我将不得不执行太多的查询才能得到上面的结果。

如果我选择嵌套文档,查询子文档是非常有限的。

mongo中的文档有16MB的限制,如果我选择嵌套文档,这就足够了。因此,我不关心文档大小。

由于mongo基本上不是用于关联和规范化的,所以我的问题是,考虑到我的上述场景,我是应该使用带关系的规范化模式,还是应该使用带嵌入文档的去规范化数据。

在MongoDB中设计数据库模式的正确方法

在MongoDB中,数据建模的指导原则是设计文档,以便轻松快速地完成应用程序最常见的查询。这与RDBMS中的模式设计非常不同,后者侧重于对数据进行规范化,以形式化数据不同部分之间的关系,然后依靠联接,通过对关系进行反规范化来获得正确的信息。MongoDB不是"为关系而设",这是不对的。的确,它不像RDBMS那样处理规范化数据,因为它不执行联接。连接必须在应用程序端完成。

Pontification完成后,一种简单的数据建模方法是将工作表存储为文档,将会话和程序数据反规范化到每个工作表中,从而简化查询

{
    "_id" : "p3s1ws0",
    "session_id" : "s1",
    "program_id" : "p3",
    ....
}

然后使用查询检索给定program_id prog_id的所有工作表

> db.worksheets.find({ "program_id" : prog_id })

最有可能添加一个排序来生成所需的表格形式。另一个现实的选择是,假设每个会话的工作表数量可以限制在一个合理的数字,比如200:

{
    "_id" : "s0",
    "program_id" : "p2",
    "worksheets" : [
        {
            "_id" : "ws0",
            ...
        },
        ...
    ],
    ...
}

查询保持相同的

db.sessions.find({ "program_id" : prog_id" })

因为您可以从每个会话中获取会话的所有工作表。根据您想要如何制作表格形式,对查询使用聚合可能是值得的,但没有迹象表明需要聚合。

两者之间的选择取决于它将如何影响您的其他查询和更新。例如,对于第一个模型,更新程序信息的成本更高,因为它需要为程序中的每个工作表更新,而不是更新程序中的每一个会话,或者如果数据被建模为具有包含工作表数组的会话数组的程序文档,则与只更新一个文档相反(可能不想这样做)。

要想了解更多关于这种数据建模的信息,我推荐William Zola在MongoDB博客中的经典系列。