如何在 MongoDB 中使用模式验证

作者选择了 开放式互联网 / 自由言论基金作为 写给捐赠计划的一部分接受捐款。

介绍

关系数据库的一个重要方面 - 这些数据库存储在由行和列组成的表中 - 是它们以已知数据类型的字段的固态,固态图表操作。

然而,可能会出现情况,您可能需要数据文档以遵循特定结构或满足某些要求. 许多文档数据库允许您定义规则,这些规则决定文档数据的部分结构,同时在需要时提供一些更改该结构的自由。

MongoDB 有一个名为方案验证的功能,允许您对文档结构应用限制。 方案验证是围绕 JSON Schema构建的,这是一个开放的标准,用于JSON文档结构描述和验证。

前提条件

要遵循本教程,您将需要:

<$>[注] **注:**有关如何配置您的服务器,安装MongoDB和安全MongoDB安装的链接教程参考Ubuntu 20.04.本教程专注于MongoDB本身,而不是潜在的操作系统。

步骤 1 – 插入文档而不应用方案验证

为了突出 MongoDB 的方案验证功能以及它们为什么有用,此步骤概述了如何打开 MongoDB 壳以连接到本地安装的 MongoDB 实例并在其内部创建样本集合。

要创建本指南中使用的样本集合,请连接到 MongoDB 壳作为您的管理用户。本教程遵循前提条件 MongoDB 安全教程的惯例,并假定该管理用户的名称是 AdminSammy,其身份验证数据库是 admin

1mongo -u AdminSammy -p --authenticationDatabase admin

在安装过程中输入密码设置以获取存取壳. 提供密码后,您将看到>提示符号。

为了说明方案验证功能,本指南的示例使用包含代表世界最高山的文件的样本数据库。

 1[label The Everest document]
 2{
 3    "name": "Everest",
 4    "height": 8848,
 5    "location": ["Nepal", "China"],
 6    "ascents": {
 7        "first": {
 8            "year": 1953,
 9        },
10        "first_winter": {
11            "year": 1980,
12        },
13        "total": 5656,
14    }
15}

本文件包含以下信息:

  • `名称':最高峰的名称。 *'高':最高峰为高地,以米为单位.
  • " 地点 " :山地所在国家。 此字段存储值为数组, 允许位于一个以上国家的山脉 。
  • scents : 此字段的值是另一个文档 。 当一个文档存储在这样的另一个文档中时,它被称为_嵌入_或_nested_文档. 每一份 " 升起 " 文件都描述了该山的成功升起。 具体地说,每份 " 升起 " 文件都包含一个 " 总 " 字段,列出每个高峰的成功升起总数。 此外,每个嵌入式文件都包含两个字段,其数值也是嵌入式文件: -第一':这个字段的价值是一个嵌入式文件,其中包含一个字段年',它描述了第一次整体成功上升的年份。 -`第一个冬季': 这个字段的值是一个嵌入式文件,其中也包含一个"年"字段,其值代表给定山上第一个成功冬季起落的年份. (英语)

运行以下insertOne()方法,在您的 MongoDB 安装中同时创建一个名为peaks的集合,并将代表 Everest 的上一个示例文档插入其中:

 1db.peaks.insertOne(
 2    {
 3        "name": "Everest",
 4        "height": 8848,
 5        "location": ["Nepal", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1953
 9            },
10            "first_winter": {
11                "year": 1980
12            },
13            "total": 5656
14        }
15    }
16)

输出将包含一个成功消息和一个新插入对象的对象标识符:

1[secondary_label Output]
2{
3        "acknowledged" : true,
4        "insertedId" : ObjectId("618ffa70bfa69c93a8980443")
5}

虽然您通过运行提供的insertOne()方法插入了此文档,但您在设计该文档的结构方面具有完全的自由性. 在某些情况下,您可能希望在数据库中的文档结构上具有一定的灵活性。

为了说明为什么这可能很重要,请考虑一些可能被输入到这个数据库的其他示例文档。

以下文档与前一文中代表珠穆朗玛峰的文档几乎相同,但没有包含一个名称字段:

 1[label The Mountain with no name at all]
 2{
 3    "height": 8611,
 4    "location": ["Pakistan", "China"],
 5    "ascents": {
 6        "first": {
 7            "year": 1954
 8        },
 9        "first_winter": {
10            "year": 1921
11        },
12        "total": 306
13    }
14}

对于包含世界上最高山的数据库,添加代表一座山的文档,但不包括其名称,很可能是一个严重的错误。

在下一个示例文档中,山的名称存在,但其高度表示为字符串而不是数字。

1[label Mountain with a string value for its height]
2{
3    "name": "Manaslu",
4    "height": "8163m",
5    "location": "Nepal"
6}

例如,如果高度属性值在文档之间存储为不同的数据类型,则无法成功地按峰值对集合进行排序。

现在运行以下insertMany()方法来测试这些文档是否可以被插入到数据库中而不会导致任何错误:

 1db.peaks.insertMany([
 2    {
 3        "height": 8611,
 4        "location": ["Pakistan", "China"],
 5        "ascents": {
 6            "first": {
 7                "year": 1954
 8            },
 9            "first_winter": {
10                "year": 1921
11            },
12            "total": 306
13        }
14    },
15    {
16        "name": "Manaslu",
17        "height": "8163m",
18        "location": "Nepal"
19    }
20])

事实证明,MongoDB不会返回任何错误,并且将成功插入两个文档:

1[secondary_label Output]
2{
3        "acknowledged" : true,
4        "insertedIds" : [
5                ObjectId("618ffd0bbfa69c93a8980444"),
6                ObjectId("618ffd0bbfa69c93a8980445")
7        ]
8}

正如此输出所示,这两个文档都是有效的JSON,这足以将它们插入集合中。然而,这不足以使数据库保持逻辑一致和有意义。

步骤 2 – 验证 string 字段

在 MongoDB 中,方案验证通过将一个 JSON 方案文件 分配给该集合来对个别集合工作。 JSON 方案是一个开放的标准,允许您定义和验证 JSON 文档的结构。

任何特定集合只能使用单个 JSON Schema,但您可以在创建集合时或随后任何时间分配一个 Schema。

若要将 JSON Schema 验证文档分配到您在上一步创建的峰值集合中,您可以执行以下命令:

1db.runCommand({
2    "collMod": "collection_name",
3    "validator": {
4        $jsonSchema: {JSON_Schema_document}
5    }
6})

runCommand方法执行collMod命令,通过应用验证器属性来修改指定的集合,而验证器属性负责方案验证,在这个示例语法中,它接受了$jsonSchema操作员。

<$>[警告] 警告:为了执行collMod命令,您的MongoDB用户必须获得相应的权限。假设您遵循了关于如何在Ubuntu 20.04上保护MongoDB的先决性教程(https://andsky.com/tech/tutorials/how-to-secure-mongodb-on-ubuntu-20-04)),并且作为您在该指南中创建的管理用户连接到您的MongoDB实例,您将需要授予它一个额外的角色,并跟随本指南中的示例。

首先,切换到用户的身份验证数据库. 在下面的示例中,这是admin,但如果不同,则连接到自己的用户身份验证数据库:

1use admin
1[secondary_label Output]
2switched to db admin

然后运行grantRolesToUser()方法,并授予用户在创建峰值集合的数据库上dbAdmin角色。

1db.grantRolesToUser(
2  "AdminSammy",
3  [ { role : "dbAdmin", db : "test" } ]
4  )

或者,您可以授予您的用户dbAdminAnyDatabase角色,正如这个角色的名称所暗示的那样,它会授予您的用户dbAdmin在您的 MongoDB 实例上的每个数据库上的特权:

1db.grantRolesToUser(
2  "AdminSammy",
3  [ "dbAdminAnyDatabase" ]
4  )

授予您的用户相应的角色后,返回您的峰值集合存储的数据库:

1use test
1[secondary_label Output]
2switched to db test

美元

请注意,当您创建一个集合时,您也可以分配一个 JSON Schema 验证器。

1db.createCollection(
2    "collection_name", {
3    "validator": {
4        $jsonSchema: {JSON_Schema_document}
5    }
6})

与上一个例子不同的是,这个语法不包括collMod命令,因为集合尚不存在,因此无法修改,但是,与上一个例子一样,collection_name是您想要分配验证文档的集合名称,而验证器选项将指定一个指定的 JSON 方案文档作为集合的验证器。

从一开始就应用JSON Schema验证器,这意味着您添加到集合的每个文档都必须满足验证器所设定的要求,但是当您将验证规则添加到现有集合时,新规则不会影响现有文档,直到您尝试修改它们。

将您转移到验证器属性的 JSON 方案文档应概述您要应用于集合的每个验证规则。

 1[label Your first JSON Schema document validating the name field]
 2{
 3    "bsonType": "object",
 4    "description": "Document describing a mountain peak",
 5    "required": ["name"],
 6    "properties": {
 7        "name": {
 8            "bsonType": "string",
 9            "description": "Name must be a string and is required"
10        }
11    },
12}

JSON Schema 文档的根部分(在属性之前的字段,在这种情况下是bsonType,描述要求)描述了数据库文档本身。

bsonType属性描述了验证引擎预计会找到的数据类型。对于数据库文档本身,预期类型是object。这意味着您只能将对象添加到这个集合中,也就是说,完整的、有效的JSON文档包围着弯曲的(})。

在 MongoDB 中,每个文档都是一个对象. 然而,JSON Schema 是一个用于描述和验证所有类型的有效 JSON 文档的标准,一个简单的数组或字符串也是有效的 JSON。

接下来,描述属性提供了本集合中发现的文档的简要描述。这个字段不需要,但除了用于验证文档外,JSON Schemas还可以用来注释文档的结构。

验证文档中的下一个属性是必需字段。必需字段只能接受包含集合中的每个文档中必须存在的文档字段列表的数组。

接下来是一个属性对象,描述了用于验证文档字段的规则. 对于您想要定义规则的每个字段,包括一个嵌入式JSON Schema文档,以该字段命名。 请注意,您可以为未列入必要数组的字段定义方案规则。

这些嵌入式方案文档将遵循与主文档相似的语法. 在本示例中,bsonType属性将要求每个文档的名称字段为字符串

若要将此JSON Schema应用于您在上一步创建的峰值集合,请运行以下 RunCommand()方法:

 1db.runCommand({
 2    "collMod": "peaks",
 3    "validator": {
 4        $jsonSchema: {
 5            "bsonType": "object",
 6            "description": "Document describing a mountain peak",
 7            "required": ["name"],
 8            "properties": {
 9                "name": {
10                    "bsonType": "string",
11                    "description": "Name must be a string and is required"
12                }
13            },
14        }
15    }
16})

MongoDB 會以成功訊息回應,表示收藏已成功修改:

1[secondary_label Output]
2{ "ok" : 1 }

之后,MongoDB将不再允许您将文档插入到峰值集合中,如果它们没有名称字段。

 1db.peaks.insertOne(
 2    {
 3        "height": 8611,
 4        "location": ["Pakistan", "China"],
 5        "ascents": {
 6            "first": {
 7                "year": 1954
 8            },
 9            "first_winter": {
10                "year": 1921
11            },
12            "total": 306
13        }
14    }
15)

这次,该操作会触发一个错误消息,表示文件验证失败:

1[secondary_label Output]
2WriteError({
3        "index" : 0,
4        "code" : 121,
5        "errmsg" : "Document failed validation",
6        . . .
7})

MongoDB 不会插入任何未能通过 JSON 方案中规定的验证规则的文档。

<$>[注] 注: 从 MongoDB 5.0 开始,当验证失败时,错误消息指向失败限制。

您也可以通过运行以下insertOne()方法来测试MongoDB是否会强制执行您在JSON Schema中包含的数据类型要求,这与上一次操作类似,但这次它包含一个名称字段。

 1db.peaks.insertOne(
 2    {
 3        "name": 123,
 4        "height": 8611,
 5        "location": ["Pakistan", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1954
 9            },
10            "first_winter": {
11                "year": 1921
12            },
13            "total": 306
14        }
15    }
16)

再次,验证将失败. 尽管存在名称字段,但它不符合要求它是字符串的限制:

1[secondary_label Output]
2WriteError({
3        "index" : 0,
4        "code" : 121,
5        "errmsg" : "Document failed validation",
6        . . .
7})

尝试一次,但在文档中存在的名称字段,然后是字符串值,这次名称是文档中的唯一字段:

1db.peaks.insertOne(
2    {
3        "name": "K2"
4    }
5)

操作将成功,文档将像往常一样接收对象标识符:

1[secondary_label Output]
2{
3        "acknowledged" : true,
4        "insertedId" : ObjectId("61900965bfa69c93a8980447")
5}

方案验证规则仅适用于名称字段,在此时,只要名称字段满足验证要求,文档将被插入无错误。

通过此,您创建了您的第一个 JSON 方案文档,并将第一个方案验证规则应用到名称字段,要求它存在并具有字符串。

步骤 3 – 验证数字字段

从步骤 1 回忆起,当您将以下文档插入到峰值集合时:

1[label Mountain with a string value for its height]
2{
3    "name": "Manaslu",
4    "height": "8163m",
5    "location": "Nepal"
6}

尽管本文档的高度值是一个字符串而不是一个数字,但您在插入本文档时使用的insertMany()方法取得了成功,因为您尚未为高度字段添加任何验证规则。

MongoDB 将接受此字段的任何值 - 即使是对该字段没有任何意义的值,如负值 - 只要插入的文档是用有效的 JSON 语法编写的。

首先,确保高度字段始终存在于新插入的文档中,并且始终以数字表示。

 1db.runCommand({
 2    "collMod": "peaks",
 3    "validator": {
 4        $jsonSchema: {
 5            "bsonType": "object",
 6            "description": "Document describing a mountain peak",
 7            "required": ["name", "height"],
 8            "properties": {
 9                "name": {
10                    "bsonType": "string",
11                    "description": "Name must be a string and is required"
12                },
13                "height": {
14                    "bsonType": "number",
15                    "description": "Height must be a number and is required"
16                }
17            },
18        }
19    }
20})

同样,在属性对象中有一个高度文档,需要任何新的高度值作为一个数字

MongoDB 會以短短的成功訊息回應,讓您知道該集合已成功修改:

1[secondary_label Output]
2{ "ok" : 1 }

现在你可以测试新的规则. 尝试插入具有通过验证文档所需的最小文档结构的文档. 下面的方法将插入包含只有两个强制性字段的文档,即名称高度:

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300
5    }
6)

融入将成功:

1[secondary_label Output]
2{
3  acknowledged: true,
4  insertedId: ObjectId("61e0c8c376b24e08f998e371")
5}

接下来,尝试插入缺少高度字段的文档:

1db.peaks.insertOne(
2    {
3        "name": "Test peak"
4    }
5)

然后尝试另一个包含高度字段,但这个字段包含一个字符串值:

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": "8300m"
5    }
6)

这两次,操作都会触发错误消息并失败:

1[secondary_label Output]
2WriteError({
3        "index" : 0,
4        "code" : 121,
5        "errmsg" : "Document failed validation",
6        . . .
7})

但是,如果你尝试插入负高度的山峰,山将保存正确:

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": -100
5    }
6)

要防止这种情况发生,您可以将一些更多属性添加到方案验证文档中. 通过执行以下操作来更换当前方案验证设置:

 1db.runCommand({
 2    "collMod": "peaks",
 3    "validator": {
 4        $jsonSchema: {
 5            "bsonType": "object",
 6            "description": "Document describing a mountain peak",
 7            "required": ["name", "height"],
 8            "properties": {
 9                "name": {
10                    "bsonType": "string",
11                    "description": "Name must be a string and is required"
12                },
13                "height": {
14                    "bsonType": "number",
15                    "description": "Height must be a number between 100 and 10000 and is required",
16                    "minimum": 100,
17                    "maximum": 10000
18                }
19            },
20        }
21    }
22})

新的最小最大属性对高度字段中的值设置了限制,确保它们不能低于100或高于10000。

现在,如果您再次尝试插入负高度值的峰值,该操作将失败:

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": -100
5    }
6)
1[secondary_label Output]
2WriteError({
3    "index" : 0,
4    "code" : 121,
5    "errmsg" : "Document failed validation",
6. . .

正如本输出所示,您的文档方案现在验证了每个文档的名称字段中的字符串值以及高度字段中的数值。

步骤 4 – 验证 Array 字段

现在,每个峰值的名称高度值正在通过方案验证限制进行验证,我们可以将注意力转向位置字段,以确保其数据的一致性。

指定山地的位置比人们预期要复杂得多,因为高峰覆盖了多个国家,这对于许多著名的八千人来说是如此。 因此,将每个高峰的位置数据存储为一个包含一个或多个国家名称的数组,而不是仅仅是一个字符串值。 与高度值一样,确保每个位置字段的数据类型在每个文档中一致,可帮助使用汇总管道总结数据。

首先,考虑一些用户可能输入的位置值的示例,并衡量哪些值是有效的或无效的:

  • [「尼泊爾」、「中國」]:這是一個兩元素的數列,並將是兩國之間的山的有效值。
  • [「尼泊爾」]:這個例子是一個單元素的數列,它也將是一個位於一個國家之上的山的有效值。
  • 「尼泊爾」:這個例子是一個平行字符串。它將是無效的,因為雖然它列出一個單一的國家,但「位置」字段應該總是包含一個數列
  • []:一個空的數列,這個例子將不是一個有效的值。

要确保 MongoDB 将这些示例的每一个正确地解释为有效或无效,请执行以下操作,为峰值集合创建一些新的验证规则:

 1db.runCommand({
 2    "collMod": "peaks",
 3    "validator": {
 4        $jsonSchema: {
 5            "bsonType": "object",
 6            "description": "Document describing a mountain peak",
 7            "required": ["name", "height", "location"],
 8            "properties": {
 9                "name": {
10                    "bsonType": "string",
11                    "description": "Name must be a string and is required"
12                },
13                "height": {
14                    "bsonType": "number",
15                    "description": "Height must be a number between 100 and 10000 and is required",
16                    "minimum": 100,
17                    "maximum": 10000
18                },
19                "location": {
20                    "bsonType": "array",
21                    "description": "Location must be an array of strings",
22                    "minItems": 1,
23                    "uniqueItems": true,
24                    "items": {
25                        "bsonType": "string"
26                    }
27                }
28            },
29        }
30    }
31})

在这个$jsonSchema对象中,该位置字段包含在需要数组中以及属性对象中,在那里,它被定义为bsonType数组,以确保位置值总是是一个数组而不是单个字符串或数字。

minItems属性验证了数组必须包含至少一个元素,而uniqueItems属性被设置为true,以确保每个位置数组中的元素都是独一无二的。

<$>[注] **注:**可用的方案文档属性为每个bsonType不同,并且根据字段类型,您将能够验证字段值的不同方面。

您可以在 JSON 方案文档中找到所有可能的验证选项的详细信息。

執行命令後,MongoDB 會以短短的成功訊息回應,表示該集合已在新的 Schema 文件中成功修改:

1[secondary_label Output]
2{ "ok" : 1 }

现在尝试插入与之前准备的示例相匹配的文档,以测试新规则的行为。

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": ["Nepal", "China"]
6    }
7)

该文档将成功插入,因为它满足所有定义的验证期望。

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": ["Nepal"]
6    }
7)

但是,如果您要运行以下任何insertOne()方法,它们会引发验证错误并失败:

1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": "Nepal"
6    }
7)
1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": []
6    }
7)
1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": ["Nepal", "Nepal"]
6    }
7)
1db.peaks.insertOne(
2    {
3        "name": "Test peak",
4        "height": 8300,
5        "location": ["Nepal", 15]
6    }
7)

根据您之前定义的验证规则,这些操作中提供的位置值被视为无效。

在遵循此步骤后,已经通过MongoDB的方案验证功能验证了描述山顶的三个主要字段,在下一步,您将学习如何使用上升字段作为示例验证嵌套文件。

步骤5:验证嵌入式文档

在此时,您的峰值集合有三个字段 – 名称高度位置 – 这些字段通过方案验证进行检查,该步骤侧重于为上升字段定义验证规则,其中描述了成功尝试达到每个峰值。

在代表珠穆朗玛峰的第一步示例文档中,上升字段结构如下:

 1[label The Everest document]
 2{
 3    "name": "Everest",
 4    "height": 8848,
 5    "location": ["Nepal", "China"],
 6    "ascents": {
 7        "first": {
 8            "year": 1953,
 9        },
10        "first_winter": {
11            "year": 1980,
12        },
13        "total": 5656,
14    }
15}

登山子文档包含一个字段,其值代表了该山的登山尝试总数。 它还包含了关于登山的第一个冬季登山以及第一个登山总体的信息。 然而,这些可能对山的描述并不重要。 毕竟,有些山可能尚未在冬季登山,或者登山日期有争议或未知。 目前,只要假定你在每个文档中总是想要的信息是登山尝试总数。

您可以更改方案验证文档,以便升起字段必须始终存在,其值必须始终是子文档。该子文档,反过来,必须始终包含包含一个大于或等于零的属性。

再次,通过运行以下 RunCommand()方法来替换peaks集合的方案验证文档:

 1db.runCommand({
 2    "collMod": "peaks",
 3    "validator": {
 4        $jsonSchema: {
 5            "bsonType": "object",
 6            "description": "Document describing a mountain peak",
 7            "required": ["name", "height", "location", "ascents"],
 8            "properties": {
 9                "name": {
10                    "bsonType": "string",
11                    "description": "Name must be a string and is required"
12                },
13                "height": {
14                    "bsonType": "number",
15                    "description": "Height must be a number between 100 and 10000 and is required",
16                    "minimum": 100,
17                    "maximum": 10000
18                },
19                "location": {
20                    "bsonType": "array",
21                    "description": "Location must be an array of strings",
22                    "minItems": 1,
23                    "uniqueItems": true,
24                    "items": {
25                        "bsonType": "string"
26                    }
27                },
28                "ascents": {
29                    "bsonType": "object",
30                    "description": "Ascent attempts information",
31                    "required": ["total"],
32                    "properties": {
33                        "total": {
34                            "bsonType": "number",
35                            "description": "Total number of ascents must be 0 or higher",
36                            "minimum": 0
37                        }
38                   }
39                }
40            },
41        }
42    }
43})

每当文档在其任何一个领域中包含子文档时,该领域的 JSON 格式都遵循与主要文档格式完全相同的语法. 就像相同的文档可以互相嵌入一样,验证格式也将它们嵌入其中。

在本 JSON Schema 文档中,‘ascents’ 字段包含在 ‘required’ 数组中,这使得它是强制性的,它也出现在 ‘properties’ 对象中,它被定义为 ‘bsonType’ 对象,就像根文件本身一样。

请注意,对上升验证的定义跟根文档具有类似的原则. 它具有必需字段,表示子文档必须包含的属性. 它还定义了一个属性列表,按照相同的结构。

上升中,有一个必需数组,其唯一值是总数,这意味着每个上升子文档将被要求包含一个总数字段。

再次,由于在本指南中没有第一第一_冬字段是强制性的,因此它们不包括在这些验证规则中。

使用此方案验证文档,请尝试从第一步插入样本 Mount Everest 文档,以验证它允许您将已确定的文档插入为有效:

 1db.peaks.insertOne(
 2    {
 3        "name": "Everest",
 4        "height": 8848,
 5        "location": ["Nepal", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1953,
 9            },
10            "first_winter": {
11                "year": 1980,
12            },
13            "total": 5656,
14        }
15    }
16)

文档成功保存,MongoDB 返回新的对象标识符:

1[secondary_label Output]
2{
3        "acknowledged" : true,
4        "insertedId" : ObjectId("619100f51292cb2faee531f8")
5}

若要确保最后的验证工作正常,请尝试插入不包含上升字段的文档:

1db.peaks.insertOne(
2    {
3        "name": "Everest",
4        "height": 8848,
5        "location": ["Nepal", "China"]
6    }
7)

这次,该操作将触发一个错误消息,指示文件验证失败:

1[secondary_label Output]
2WriteError({
3        "index" : 0,
4        "code" : 121,
5        "errmsg" : "Document failed validation",
6        . . .
7})

现在尝试插入一个文档,其上升子文档缺少字段:

 1db.peaks.insertOne(
 2    {
 3        "name": "Everest",
 4        "height": 8848,
 5        "location": ["Nepal", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1953,
 9            },
10            "first_winter": {
11                "year": 1980,
12            }
13        }
14    }
15)

这将再次引发错误。

作为最后的测试,请尝试输入包含上升字段的文档,该字段具有值,但此值为负值:

 1db.peaks.insertOne(
 2    {
 3        "name": "Everest",
 4        "height": 8848,
 5        "location": ["Nepal", "China"],
 6        "ascents": {
 7            "first": {
 8                "year": 1953,
 9            },
10            "first_winter": {
11                "year": 1980,
12            },
13            "total": -100
14        }
15    }
16)

由于负的值,本文档也将失败验证测试。

结论

通过遵循本教程,您了解了 JSON Schema 文档以及如何使用它们来验证文档结构,然后将其保存到一个集合中。

MongoDB 的方案验证功能不应该被认为是应用级数据验证的替代品,但它可以进一步保护免受数据限制的侵犯,这对于保持数据有意义至关重要。使用方案验证可以成为结构化数据的有用工具,同时保持数据存储的无计划方法的灵活性。

教程只描述了MongoDB的方案验证功能的一小组。您可以将更多的限制应用到不同的MongoDB数据类型,甚至可以更改验证行为的严格性,并使用JSON Schema来过滤和验证现有文档。

Published At
Categories with 技术
comments powered by Disqus