2.3设计文档
到这里,我相信你一定在问自己:如果文档的基本结构是JSON(非常简单和文本的东西),什么会导致创建NoSQL数据库如此复杂?
让我们来看看!首先,是的!你疑问是对的。NoSQL数据库可以非常简单。但是,这并不意味着它们的结构不会比关系数据库的结构复杂。不过,它会有所不同!
如前所述,集合不会强制您事先定义文档的结构。但这肯定是你必须在某个时候做出的决定。这个决定会影响重要的方面,特别是在查询的性能方面。
现在,您很可能也会问自己,这些应用程序如何表示文档之间的关系。如果你直到现在才想到这个,那不是你的错。我们习惯于思考关系世界,比如想知道学生和他们的班级之间,或者产品与订单之间的关系。
MongoDB也有自己的表示这种关系的方式。其实有两种方法:
嵌入式文档(Embeddeddocuments);
引用(Reference)。
2.3.1使用嵌入式文档
通过使用子文档,我们可以构建更复杂和优化的数据结构。因此,当我们建模文档时,我们可以选择将相关数据嵌入到一个文档中。
将数据嵌入到一个文档中的决定,通常与获得更好的读取性能的意图有关,因为使用一个查询我们可以完全检索我们需要的信息。
看下面的示例:
{
id: 1,
title: "MongoDBData Modeling Blog post",
body: "MongoDBData Modeling....",
author: "Wilsonda Rocha França",
date:ISODate("2014-11-19"),
comments: [
{
name:"Mike",
comment:"Mike comment...."
},
{
name:"Tom",
comment:"Tom comment...."
},
{
name:"Yuri",
comment:"Yuri comment...."
}
],
tags:["mongodb", "modeling", "nosql"]
}
附上述代码截图如下:
正如我们可以推论的,这个文档代表了一篇博文。这种文档的优点是,只需一个查询,我们就可以获得所有需要呈现给用户的数据。这同样适用于更新:只需一个查询,我们可以修改此文档的内容。不过,当我们决定嵌入数据时,我们必须确保文档不超过16 MB的BSON大小限制。
在MongoDB中嵌入数据时没有规则,但总的来说,我们应该观察:
•我们在文档之间是否有一对一的关系。
•文档之间是否存在一对多关系,以及关系中的"多"部分是否非常依赖于"一"部分。举例来说,这意味着每次我们展示"一"部分时,我们也会呈现这种关系的"多"部分。
如果我们的模型符合上述情况之一,我们应该考虑使用嵌入式文档。
2.3.2使用引用
规范化是帮助构建关系数据模型的基本过程。为了尽量减少冗余,在这个过程中,我们将较大的表分成较小的表并定义它们之间的关系。可以说在MongoDB中创建一个引用,是我们必须"正常化"我们模型的方式。该引用将描述文件之间的关系。
您可能会对我们为什么要考虑非关系世界中的关系感到困惑,但这并不意味着关系在NoSQL数据库中不存在。我们将经常使用关系建模的概念来解决常见问题。如前所述,为了消除冗余,文档可以互相引用。
可是等等!从现在开始你应该知道一些非常重要的事情:MongoDB不支持连接运算(joins)。这意味着,即使参考了其他文档,您也必须至少执行两次查询才能获取所需的完整信息。
看下面的例子:
{
_id: 1,
name : "Product1",
description: "Product 1description",
price: "$10,00",
supplier : {
name: "Supplier1",
address: "St.1",
}
}
{
_id: 2,
name : "Product2",
description: "Product 2description",
price: "$10,00",
supplier : {
name: "Supplier1",
address: "St.1",
}
}
{
_id: 3,
name : "Product 3",
description: "Product 3description",
price: "$10,00",
supplier : {
name: "Supplier1",
address:"St.1",
}
}
附上述代码截图如下:
在前面的例子中,我们有来自产品集合的文档。我们可以看到,在三种产品的实例中,我们对供应商密钥具有相同的价值。我们可以有两个集合:产品和供应商(products和suppliers),而不是这种重复的数据,我们可以在下面的例子中看到:
供应商(suppliers)
suppliers
{
_id: 1
name: "Supplier 1",
address: "St.1",
products: [1, 2, 3]
}
产品(products)
{
_id: 1,
name : "Product 1",
description: "Product 1 description",
price: "$10,00"
}
{
_id: 2,
name : "Product 2",
description: "Product 2 description",
price: "$10,00"
}
{
_id: 3,
name : "Product 3",
description: "Product 3 description",
price: "$10,00"
}
在这种特殊情况下,由供应商提供一些产品,参考供应商的产品选择是很好的。但是,如果情况恰恰相反,那么更好的方法是:
供应商-suppliers
{
_id: 1
name: "Supplier 1",
address: "St.1",
}
产品-products
{
_id: 1,
name : "Product 1",
description: "Product 1 description",
price: "$10,00",
supplier: 1
}
{
_id: 2,
name : "Product 2",
description: "Product 2 description",
price: "$10,00",
supplier: 1
}
{
_id: 3,
name : "Product 3",
description: "Product 3 description",
price: "$10,00",
supplier: 1
}
对于使用MongoDB的引用是没有规则的,但总的来说,我们应该注意到:
•嵌入数据时是否多次复制相同的信息(这表明读取性能不佳)
•是否需要呈现多对多的关系
•的模型是否是一个层次结构
如果我们的模型符合上述情况之一,我们应该考虑使用引用。
2.3.3原子性
设计文档时影响我们决策的另一个重要概念是原子性。在MongoDB中,操作在文档级别是原子性的。这意味着我们可以一次修改一个文档。即使我们有一个在集合(相当于表)中的多个文档中工作的操作,该操作一次只能在一个文档(一条记录-表行)中进行。(为什么?_Id唯一)
因此,当我们决定使用嵌入数据对文档进行建模时,我们只需编写操作,因为我们需要的所有数据都在同一个文档中。这与我们选择引用数据时发生的情况相反,在这种情况下,我们需要许多不是原子的写入操作。
本节设计文档的内容到此为止,下一节讲解:4.通用文档模式敬请继续阅读。
码字很辛苦,顺手就打赏点呗~^_^
领取专属 10元无门槛券
私享最新 技术干货