了解文档

文档数据库用于将半结构化数据存储为文档,— 而不是像关系数据库那样在多个表之间对数据进行规范化,每个表都有唯一的固定结构。存储在文档数据库中的文档使用嵌套键值对来提供文档的结构或架构。不过,不同类型的文档可以存储在同一文档数据库中,从而满足了处理不同格式的类似数据的要求。例如,由于每个文档都是自描述的,主题文档数据库中的示例文档中所述的在线存储的 JSON 编码文档可以存储在同一个文档数据库中。

SQL 与非关系术语

下表对文档数据库 (MongoDB) 使用的术语与 SQL 数据库使用的术语进行了比较。

SQLMongoDB

集合

文档

字段

主键

ObjectId

Index

Index

查看

查看

嵌套表或对象

嵌入文档

数组

数组

简单文档

文档数据库中的所有文档都是自描述的。虽然此文档使用类似 JSON 格式的文档,但您可以使用其他编码方式。

简单文档具有一个或多个字段,这些字段在文档中都处于同一级别。在以下示例中,字段 SSNLNameFNameDOBStreetCityState-ProvincePostalCodeCountry 在文档中属于同级。

  1. {
  2. "SSN": "123-45-6789",
  3. "LName": "Rivera",
  4. "FName": "Martha",
  5. "DOB": "1992-11-16",
  6. "Street": "125 Main St.",
  7. "City": "Anytown",
  8. "State-Province": "WA",
  9. "PostalCode": "98117",
  10. "Country": "USA"
  11. }

在简单文档中组织信息时,每个字段将被单独管理。要检索个人的地址,必须作为单个数据项检索 StreetCityState-ProvincePostalCodeCountry

嵌入文档

复杂文档通过在文档中创建嵌入文档来组织数据。嵌入文档帮助管理分组中作为单个数据项的数据,这些数据项在特定情况下效率更高。使用上述示例,您可以在主文档中嵌入 Address 文档。这样做会生成以下文档结构:

  1. {
  2. "SSN": "123-45-6789",
  3. "LName": "Rivera",
  4. "FName": "Martha",
  5. "DOB": "1992-11-16",
  6. "Address":
  7. {
  8. "Street": "125 Main St.",
  9. "City": "Anytown",
  10. "State-Province": "WA",
  11. "PostalCode": "98117",
  12. "Country": "USA"
  13. }
  14. }

现在,您可以作为单个字段 ( "SSN": )、嵌入文档 ( "Address": ) 或嵌入文档的成员 ( "Address":{"Street":} ) 对文档中的数据进行访问。

文档数据库中的示例文档

如上所述,因为数据库中的每个文档是自描述的,文档数据库中的文档结构可能彼此不同。以下两个文档,一个是图书文档,另一个是为期刊文档,在结构上有所不同。不过,它们可以位于同一个文档数据库中。

下面是一个示例图书文档:

  1. {
  2. "_id" : "9876543210123",
  3. "Type": "book",
  4. "ISBN": "987-6-543-21012-3",
  5. "Author":
  6. {
  7. "LName":"Roe",
  8. "MI": "T",
  9. "FName": "Richard"
  10. },
  11. "Title": "Understanding Document Databases"
  12. }

以下是带有两篇文章的示例期刊文档:

  1. {
  2. "_id" : "0123456789012",
  3. "Publication": "Programming Today",
  4. "Issue":
  5. {
  6. "Volume": "14",
  7. "Number": "09"
  8. },
  9. "Articles" : [
  10. {
  11. "Title": "Is a Document Database Your Best Solution?",
  12. "Author":
  13. {
  14. "LName": "Major",
  15. "FName": "Mary"
  16. }
  17. },
  18. {
  19. "Title": "Databases for Online Solutions",
  20. "Author":
  21. {
  22. "LName": "Stiles",
  23. "FName": "John"
  24. }
  25. }
  26. ],
  27. "Type": "periodical"
  28. }

比较这两个文档的结构。借助关系数据库,您需要单独的“periodical”和“books”表或未使用字段的单个表作为 null 值,例如“发布”、“问题”、“文章”和“MI”。由于文档数据库是半结构化的,每个文档都定义了自己的结构,因此这两个文档可以在同一个文档数据库中共存,而没有 null 字段。文档数据库善于处理稀疏数据。

针对文档数据库进行开发,可以实现快速、迭代的开发。这是因为您可以动态地更改文档的数据结构,而不必更改整个集合的架构。文档数据库非常适合敏捷开发和动态变化的环境。

了解文档数据库中的规范化

文档数据库未规范化;在一个文档中发现的数据可以在另一个文档中重复。此外,文档之间可能存在一些数据差异。例如,假设您在网上商店购物,所有购物的详细信息都存储在一个文档中。文档应类似于以下 JSON 文档:

  1. {
  2. "DateTime": "2018-08-15T12:13:10Z",
  3. "LName" : "Santos",
  4. "FName" : "Paul",
  5. "Cart" : [
  6. {
  7. "ItemId" : "9876543210123",
  8. "Description" : "Understanding Document Databases",
  9. "Price" : "29.95"
  10. },
  11. {
  12. "ItemId" : "0123456789012",
  13. "Description" : "Programming Today",
  14. "Issue": {
  15. "Volume": "14",
  16. "Number": "09"
  17. },
  18. "Price" : "8.95"
  19. },
  20. {
  21. "ItemId": "234567890-K",
  22. "Description": "Gel Pen (black)",
  23. "Price": "2.49"
  24. }
  25. ],
  26. "PaymentMethod" :
  27. {
  28. "Issuer" : "MasterCard",
  29. "Number" : "1234-5678-9012-3456"
  30. },
  31. "ShopperId" : "1234567890"
  32. }

所有这些信息都作为文档存储在交易集合中。后来,您意识到忘记购买一件物品。因此,您再次登录同一家商店,进行另一次购买,这也是作为另一个文档存储在交易集合中。

  1. {
  2. "DateTime": "2018-08-15T14:49:00Z",
  3. "LName" : "Santos",
  4. "FName" : "Paul",
  5. "Cart" : [
  6. {
  7. "ItemId" : "2109876543210",
  8. "Description" : "Document Databases for Fun and Profit",
  9. "Price" : "45.95"
  10. }
  11. ],
  12. "PaymentMethod" :
  13. {
  14. "Issuer" : "Visa",
  15. "Number" : "0987-6543-2109-8765"
  16. },
  17. "ShopperId" : "1234567890"
  18. }

请注意这两个文档之间的冗余 — 您的姓名和购物者 ID(此外,如果您使用相同的信用卡,您的信用卡信息)。但这没关系,因为存储成本低廉,每个文档都完整记录了单个交易,只需简单的键值查询就可以快速检索,不需要连接。

两个文档之间也存在明显差异 — 您的信用卡信息。这只是一个明显差异,因为可能您每次购买都使用不同的信用卡。每个文档对其记录的交易都是准确的。