作者选择Open Internet/Free Speech Fund]接受捐赠,作为WRITE For Goods计划)的一部分。
简介
尽管它们最初是在几十年前发明的,但基于计算机的数据库在今天的互联网上已经变得无处不在。越来越常见的是,网站和应用程序涉及从数据库收集、存储和检索数据。多年来,数据库领域一直由关系型databases,]主导,它将数据组织在由行组成的表中。然而,为了摆脱关系模型强加的僵化结构,近年来出现了许多不同的数据库类型。
这些新的数据库模型统称为NoSQL数据库,因为它们通常不使用关系数据库通常用来管理和查询数据的结构化查询语言。NoSQL数据库在数据结构方面提供了高度的可伸缩性和灵活性。这些特性使NoSQL数据库对于处理大量数据和快速、敏捷的开发非常有用。
这篇概念性文章概述了与文档数据库相关的关键概念以及使用它们的好处。本文中使用的示例引用了MongoDB,这是一个广泛使用的面向文档的数据库,但是这里强调的大多数概念也适用于大多数其他文档数据库。
什么是文档库?
文档数据库不再认为数据库是由行和列组成的,而是将数据存储为_DOCUMENTS_,这是关系数据库中的表的情况。您可能会认为文档是一个自包含的数据条目,其中包含理解其含义所需的所有内容,类似于现实世界中使用的文档。
下面是一个可能出现在文档数据库(如MongoDB)中的文档示例。此示例文档代表一张公司联系人卡片,描述了一个名为Sammy
的员工:
1[label Sammy's contact card document]
2{
3 "_id": "sammyshark",
4 "firstName": "Sammy",
5 "lastName": "Shark",
6 "email": "[email protected]",
7 "department": "Finance"
8}
请注意,该文档被编写为JSON对象。JSON是一种人类可读的数据格式,近年来变得相当流行。虽然可以使用许多不同的格式来表示文档数据库中的数据,如XML或YAML,但JSON是最常见的选择之一。例如,MongoDB采用JSON作为主要的数据格式来定义和管理数据。
JSON文档中的所有数据都表示为field:value
形式的字段-值对。在前面的示例中,第一行显示了一个_id
字段,值为sammyShark
。该示例还包括员工的名字和姓氏、他们的电子邮件地址以及他们在哪个部门工作的字段。
字段名使您只需一目了然,即可了解文档中包含的数据类型。文档数据库中的文档是自描述的,这意味着它们既包含数据值,也包含有关正在存储的数据类型的信息。当从数据库中检索文档时,您总是可以获得完整的信息。
下面是另一个示例文档,表示Sammy的一个名为Tom
的同事,他在多个部门工作,也使用中间名:
1[label Tom's contact card document]
2{
3 "_id": "tomjohnson",
4 "firstName": "Tom",
5 "middleName": "William",
6 "lastName": "Johnson",
7 "email": "[email protected]",
8 "department": ["Finance", "Accounting"]
9}
第二个文档与第一个示例有一些不同。例如,它添加了一个名为midleName
的新字段。此外,该文档的Department
字段存储的不是单个值,而是由两个值组成的数组:财务
和会计
。
因为这些文档包含不同的数据字段,所以可以说它们具有不同的模式。数据库的模式是它的形式结构,它勾勒出它可以保存的数据类型。对于文档,它们的模式反映在它们的字段名以及这些字段代表的值的类型中。
在关系数据库中,您无法将这两个示例联系人卡片存储在同一个表中,因为它们的结构不同。您必须调整数据库模式以允许存储多个部门和中间名,并且必须为Sammy提供中间名,或者使用NULL
值填充该行的列。文档数据库则不是这样,它允许您自由地保存具有不同模式的多个文档,而无需更改数据库本身。
在文档数据库中,文档不仅是自描述的,而且它们的模式是_DYNAMIC_,这意味着在开始保存数据之前不必定义它。同一数据库中的不同文档之间的字段可以不同,您可以随意修改文档的结构,随时随地添加或删除字段。文档也可以嵌套-这意味着一个文档中的一个字段可以具有由另一个文档组成的值-从而可以在单个文档条目中存储复杂的数据。
假设联系人卡片必须存储有关员工使用的社交媒体帐户的信息,并将它们作为嵌套对象添加到文档中:
1[label Tom's contact card document with social media accounts information attached]
2{
3 "_id": "tomjohnson",
4 "firstName": "Tom",
5 "middleName": "William",
6 "lastName": "Johnson",
7 "email": "[email protected]",
8 "department": ["Finance", "Accounting"],
9 "socialMediaAccounts": [
10 {
11 "type": "facebook",
12 "username": "tom_william_johnson_23"
13 },
14 {
15 "type": "twitter",
16 "username": "@tomwilliamjohnson23"
17 }
18 ]
19}
文档中出现了一个名为Social MediaAcCounts
的新字段,但它不是指单个值,而是指描述单个社交媒体帐户的一组嵌套对象。这些帐户中的每一个都可以是单独的文档,但在这里它们直接存储在联系人卡中。同样,不需要更改数据库结构来满足这一要求。您可以立即将新文档保存到数据库。
<$>[备注]
注意: 在MongoDB中,字段和集合的命名习惯使用camelCase
表示法,单词之间没有空格,第一个单词完全小写,其他单词的第一个字母大写。也就是说,你也可以使用不同的符号,比如Snake_Case
,在这种符号中,单词都是小写的,并用下划线分隔。无论您选择哪种表示法,最好是在整个数据库中一致地使用它。
<$>
从开发人员的角度来看,所有这些属性使得使用文档数据库变得直观。该数据库便于在应用程序中存储描述数据的实际对象,鼓励进行实验,并在随着软件的增长和发展而重塑数据时提供极大的灵活性。
文档数据库的好处
虽然面向文档的数据库可能不是每个用例的正确选择,但选择一个而不是关系数据库有很多好处。其中最重要的几个好处是:
- 灵活性和适应性 :通过对数据结构的高度控制,文档数据库能够进行实验并适应新出现的要求。可以立即添加新的字段,并且可以随时更改现有的字段。这是由开发人员决定是否必须修改旧的文档,还是只能在未来实现更改。
- 结构化和非结构化数据管理能力 :如前所述,关系数据库非常适合存储符合刚性结构的数据。文档数据库也可用于处理结构化数据,但在必要时也可用于存储非结构化数据。您可以将结构化数据想象为在包含行和列的电子表格中轻松表示的那种信息,而非结构化数据并非如此简单易懂。非结构化数据的例子包括包含人类生成的文本和多媒体的丰富社交媒体帖子,不遵循统一格式的服务器日志,或者来自智能家居中大量不同传感器的数据。
- 设计的可扩展性 :关系数据库通常是写受限的,提高它们的性能需要您_垂直扩展_(这意味着您必须将它们的数据迁移到更强大、更高性能的数据库服务器上)。相反,文档数据库被设计为分布式系统,允许您水平扩展(这意味着您将单个数据库分散到多个服务器上)。因为文档是同时包含数据和模式的独立单元,所以将它们分布在服务器节点上相对简单。这使得能够以较低的操作复杂性存储大量数据。
在实际应用程序中,文档数据库和其他NoSQL和关系数据库经常一起使用,每个数据库负责它最适合的内容。这种混合各种类型的数据库的范例称为多语言持久化。
文档入库
虽然文档数据库在文档的结构方面具有很大的灵活性,但拥有一些将数据组织成具有相似特征的类别的方法对于确保数据库健康和可管理至关重要。
想象一下,一个数据库是公司档案中的一个单独的橱柜,有许多抽屉。例如,一个抽屉可能保存雇佣合同的记录,而另一个抽屉保存与商业伙伴的协议。虽然在技术上可以将这两种文档放在一个抽屉中,但稍后要浏览这些文档会很困难。
在文档数据库中,这样的抽屉通常称为集合,在逻辑上类似于关系数据库中的表。集合的作用是将共享相似逻辑功能的文档组合在一起,即使单个文档的架构可能略有不同。例如,假设您有一份固定期限的雇佣合同,而另一份合同描述了承包商的额外福利。这两份文件都是雇佣合同,因此,将它们归入一个集合可能是有意义的:
<$>[备注] 注意: 虽然这是一种流行的方法,但并不是所有的文档数据库都使用集合的概念将文档组织在一起。一些数据库系统使用标记或树状层次结构,其他数据库系统直接将文档存储在数据库中,没有进一步的细分。MongoDB是流行的面向文档的数据库之一,它使用集合来组织文档。 <$>
集合中的文档之间具有相似的特征还允许您构建索引,以便基于与某些字段相关的查询更高效地检索文档。索引是一种特殊的数据结构,它以更快的遍历和筛选方式存储集合的一部分数据。
例如,您可能在一个数据库中有一个文档集合,这些文档都共享一个相似的字段。因为每个文档共享相同的字段,所以您很可能会在运行查询时经常使用该字段。在没有索引的情况下,任何请求数据库检索特定文档的查询都需要一个集合扫描--逐个浏览集合中的所有文档以找到请求的匹配。但是,通过创建索引,数据库只需要浏览索引字段,从而提高了查询性能。
数据类型和模式验证
虽然我们提到了面向文档的数据库可以以不同的格式存储文档,如XML、YAML或JSON,但这些格式通常会通过特定于给定数据库系统的附加特性进一步扩展,例如附加的数据类型或结构验证特性。
例如,MongoDB在内部使用名为bson(二进制JSON的缩写)的二进制格式,而不是纯JSON。这不仅允许更好的性能,而且还使用JSON本身不支持的数据类型扩展了格式。多亏了这一点,我们可以可靠地在MongoDB文档中存储不同类型的数据,而不受标准JSON类型的限制,并使用特定于单个数据类型的过滤、排序和聚合功能。
下面的示例文档使用了MongoDB支持的几种不同的数据类型:
1{
2 "_id": ObjectId("5a934e000102030405000000"),
3 "code": NumberLong(2090845886852),
4 "image": BinData(0, "TGVhcm5pbmcgTW9uZ29EQg=="),
5 "lastPurchased": ISODate("2021-01-19T06:01:17.171Z"),
6 "name": "Document database sticker",
7 "price": NumberDecimal("13.23"),
8 "quantity": 317,
9 "tags": [
10 "stickers",
11 "accessories"
12 ]
13}
请注意,其中一些数据类型不是JSON的典型数据类型,例如精确精度的十进制数字或表示为对象的日期,如NumberDecimal
或ISODate
。这确保这些字段将始终被正确解释,而不会错误地转换为另一个类似的数据类型,如将十进制数转换为常规双精度型。
这种受支持的数据类型与模式验证功能相结合,使得实现一组规则和有效性要求成为可能,从而提供文档数据库结构。这不仅允许您对非结构化数据建模,还允许您按照更严格和更精确的要求创建文档集合。
结论
由于其灵活性、可伸缩性和易用性,文档数据库正成为应用程序开发人员日益流行的数据库选择。它们非常适合不同的应用程序,单独工作或作为更大的多数据库生态系统的一部分工作得很好。面向文档的数据库种类繁多,具有明显的优势和用例,可以为任何给定的任务选择最佳数据库。
您可以从DigitalOcean的关于该主题的社区文章.)了解更多面向文档的数据库和其他NoSQL数据库
为了更多地了解MongoDB,我们鼓励您遵循本系列教程,该系列教程涵盖了许多关于使用和管理MongoDB的主题,并查看MongoDB官方文档,),这是关于MongoDB以及一般文档数据库的大量知识来源。