假设您想要模拟某些情况。公司可以有一个或多个分支机构。这些分支机构的员工可以在不同的公司(甚至同一公司的两个不同分支机构)工作。这当然只是一个例子。
我们还假设大多数搜索/查询将在员工和公司集合上完成。
首先(天真)这样做的方法是嵌入所有东西(公司有分支和分支的数组有员工阵列):
{
name: "Company name",
// other company data
branches : [
{
name: "Branch name",
// other branch data
Employees: [
{
// employee1 data
},
{
// employee data
},
]
}
]
}
但是当人们有兴趣检索员工信息时,这将是非常低效的(人们必须检索公司,然后遍历每个分支以找到所需的员工)。
另一方面,可以使用引用并模仿RDBMS(会有Company,Branch和Employee集合),但这意味着会有更多查询。
第三个选项(我最接近),将Employee作为一个单独的集合,然后在Branches中有一个对它的引用数组。此外,为了允许更快的查询,例如:“具有特定名称的员工,适用于某个公司和某个分支”,公司ObjectId可以存储在Employee集合中:
{
company_id: "some id",
first_name: "First name",
last_name: "Last name",
//
}
因此,在这种情况下,要搜索具有某些公司和特定分支的某些名称的所有员工,就必须进行两次查询。第一个查询将返回满足“公司条件”(公司名称和分支名称)的公司,然后对Employee集合的第二个查询将返回所有具有指定名称且在第一个查询中返回其ID的公司中工作的员工。
你会以其他方式这样做吗?有没有其他“推荐”的方法来做到这一点?你会添加一些改进吗?
更重要的是,当这两个查询返回具有小交集的结果集时,该怎么办?在这种情况下如何提高绩效?
答案 0 :(得分:4)
我认为你主要是朝着正确的方向前进。
虽然有些情况下MongoDB中的非规范化并不像关系数据库那样邪恶,但事实上正确的做法,你可以在这里使用多个集合。那是因为MongoDB文档的上限为16MB。如果你有一个非常大的公司,有很多分支机构,有很多员工,而且员工子文档变得更加复杂,你可以很容易地破解这个限制。
从员工到公司的参考是一个好主意。但是你应该考虑不使用公司的_id字段,而是使用公司名称和分支名称,只要你能保证它们的每个组合在公司集合中是唯一的(就像这两个上的唯一复合索引一样)字段)。原因是当您查找员工时,您通常还需要公司和分支机构的名称。如果您只有_id,则必须执行其他查询才能获取该信息。
您说您在分支机构和员工之间没有1:n关系,而是n:m关系。在这种情况下,我建议你为每个员工添加一个“任务”数组,其中包含有两个字段的对象,company_name和company_branch(也许你想添加第三个字段“position”,表明他或她在做什么有)。
您的员工文件将如下所示:
{
first_name: "First name",
last_name: "Last name",
//
assignments: [
{ company:"Aperture Science", branch:"R&D", position:"test subject" },
{ company:"Black Mesa", branch:"security", position:"leader of blue shift" }
]
}
请注意,您可以在此处使用无模式数据库的优势:您可以轻松拥有不仅拥有分支机构,而且拥有更多层次结构级别(如部门和组)的公司,以及其他不具备分支机构级别的公司。
但是当我想重命名公司或分公司时呢?
在这种情况下,您必须更新引用重命名的公司/分支的每个员工文档。是的,对于那种情况,它不是最有效的架构。但请记住,MongoDB模式应始终针对最常见的用例进行优化。您认为会更频繁地发生什么:a)公司或分公司被重命名或b)有人想要查找员工?