Database Manual / Data Modeling / Schema Validation

Specify Validation for Polymorphic Collections指定多态集合的验证

You can specify schema validation for a collection that stores polymorphic data, or documents with varying structures or schemas.您可以为存储多态数据的集合或具有不同结构或模式的文档指定模式验证。

To create schema validation for multiple schemas within a single collection, you can set the schemas in your validation rules and ensure that documents conform to one of your collection's schemas.要为单个集合中的多个模式创建模式验证,可以在验证规则中设置模式,并确保文档符合集合的模式之一。

About this Task关于此任务

Consider a collection, accounts, that stores data on customers of a bank and their account details. The collection contains both customer documents and account documents.考虑一个集合,accounts,它存储银行客户及其帐户详细信息的数据。该集合包含customer文档和account文档。

The following code inserts two customer documents into the accounts collection to store the details of customers Andrew and Anne, respectively. 以下代码将两个customer文档插入到accounts集合中,分别存储客户Andrew和Anne的详细信息。It also inserts two account documents to represent each of their individual savings accounts and a third account document to represent their shared checking account. 它还插入了两份account文件,分别代表他们的个人储蓄账户和第三份account文件。You can run the code for this tutorial in the MongoDB Shell (mongosh).您可以在MongoDB Shell(mongosh中运行本教程的代码。

db.accounts.insertMany( [
{
"customerId": "CUST-123456789",
"docType": "customer",
"name": {
"title": "Mr",
"first": "Andrew",
"middle": "James",
"last": "Morgan"
},
"address": {
"street1": "240 Blackfriars Rd",
"city": "London",
"postCode": "SE1 8NW",
"country": "UK"
},
"customerSince": ISODate("2005-05-20")
},
{
"customerId": "CUST-987654321",
"docType": "customer",
"name": {
"title": "Mrs",
"first": "Anne",
"last": "Morgan"
},
"address": {
"street1": "240 Blackfriars Rd",
"city": "London",
"postCode": "SE1 8NW",
"country": "UK"
},
"customerSince": ISODate("2003-12-01")
},
{
"accountNumber": "ACC1000000654",
"docType": "account",
"accountType": "checking",
"customerId": [
"CUST-123456789",
"CUST-987654321"
],
"dateOpened": ISODate("2003-12-01"),
"balance": Decimal128("5067.65")
},
{
"accountNumber": "ACC1000000432",
"docType": "account",
"accountType": "savings",
"customerId": [
"CUST-123456789"
],
"dateOpened": ISODate("2005-10-28"),
"balance": Decimal128("10341.21")
},
{
"accountNumber": "ACC1000000890",
"docType": "account",
"accountType": "savings",
"customerId": [
"CUST-987654321"
],
"dateOpened": ISODate("2003-12-15"),
"balance": Decimal128("10341.89")
}
] );

To only allow documents that adhere to the customer or account schemas into the accounts collection, set up schema validation using the following procedure.要只允许符合customeraccount模式的文档进入accounts集合,请使用以下过程设置模式验证。

Steps步骤

1

Create a JSON schema definition for each type of document为每种类型的文档创建JSON模式定义

To distinguish between different types of documents, you can use multiple JSON schemas. To define what attributes need to be in a document and what data types they accept, create two schemas: one for a customer document, and one for an account document. Each schema includes a docType attribute to identify which type of entity it represents.为了区分不同类型的文档,您可以使用多个JSON模式。要定义文档中需要哪些属性以及它们接受哪些数据类型,请创建两个模式:一个用于customer文档,一个用于account文档。每个模式都包含一个docType属性,用于标识它所代表的实体类型。

const customerSchema = {
required: ["docType", "customerId", "name", "customerSince"],
properties: {
docType: { enum: ["customer"] },
customerId: { bsonType: "string"},
name: {
bsonType: "object",
required: ["first", "last"],
properties: {
title: { enum: ["Mr", "Mrs", "Ms", "Dr"]},
first: { bsonType: "string" },
middle: { bsonType: "string" },
last: { bsonType: "string" }
}
},
address: {
bsonType: "object",
required: ["street1", "city", "postCode", "country"],
properties: {
street1: { bsonType: "string" },
street2: { bsonType: "string" },
postCode: { bsonType: "string" },
country: { bsonType: "string" }
}
},
customerSince: {
bsonType: "date"
}
}
};

const accountSchema = {
required: ["docType", "accountNumber", "accountType", "customerId", "dateOpened", "balance"],
properties: {
docType: { enum: ["account"] },
accountNumber: { bsonType: "string" },
accountType: { enum: ["checking", "savings", "mortgage", "loan"] },
customerId: { bsonType: "array" },
dateOpened: { bsonType: "date" },
balance: { bsonType: "decimal" }
}
};
2

Configure the collection to only accept the appropriate documents将集合配置为只接受适当的文档

To allow documents that match either the customerSchema or the accountSchema, use the oneOf JSON schema operator. 要允许与customerSchemaaccountSchema匹配的文档,请使用oneOf JSON模式运算符。Then, use the collMod command to update the accounts collection to use to your schema validation.然后,使用collMod命令更新要用于架构验证的帐户集合。

db.runCommand({
collMod: "accounts",
validator: { $jsonSchema: { oneOf: [ customerSchema, accountSchema ] } }
})
3

Add extra semantic validations添加额外的语义验证

You can optionally add extra semantic validations. For example, you can add the following constraints to your collection’s documents:您可以选择添加额外的语义验证。例如,您可以将以下约束添加到集合的文档中:

  • For customer documents, the customerSince value can't be any earlier than the current time.对于customer文档,customerSince值不能早于当前时间。
  • For account documents, the dateOpened value can't be any earlier than the current time.对于account文档,dateOpened值不能早于当前时间。
  • For savings accounts, the balance can't fall below zero.对于储蓄账户,balance(余额)不能低于零。

You can implement the extra validations by identifying invalid customer and account documents and implementing those constraints into your schema validation.您可以通过识别无效的customeraccount文档并将这些约束实施到模式验证中来实现额外的验证。

const invalidCustomer = {
"$expr": { "$gt": ["$customerSince", "$$NOW"] }
};

const invalidAccount = {
$or: [
{
accountType: "savings",
balance: { $lt: 0}
},
{
"$expr": { "$gt": ["$dateOpened", "$$NOW"]}
}
]
};
const schemaValidation = {
"$and": [
{ $jsonSchema: { oneOf: [ customerSchema, accountSchema ] }},
{ $nor: [
invalidCustomer,
invalidAccount
]
}
]
};

db.runCommand({
collMod: "accounts",
validator: schemaValidation
})
4

Verify the documents in your collection核实您集合的文件

To verify that all the documents already in your collection adhere to your new schema validation, use the db.collection.validate() command.要验证集合中已有的所有文档是否符合新的模式验证,请使用db.collection.validate()命令。

db.accounts.validate()
{
ns: '66cf8508e64dbb03ce45b30e_test.accounts',
uuid: UUID('1aedf62a-f202-4e7c-b434-879057bb6d6b'),
nInvalidDocuments: 0,
nNonCompliantDocuments: 0,
nrecords: 10,
nIndexes: 1,
keysPerIndex: { _id_: 10 },
indexDetails: { _id_: { valid: true } },
valid: true,
repaired: false,
readTimestamp: Timestamp({ t: 1749235730, i: 26 }),
warnings: [],
errors: [],
extraIndexEntries: [],
missingIndexEntries: [],
corruptRecords: [],
ok: 1,
'$clusterTime': {
clusterTime: Timestamp({ t: 1749235753, i: 31 }),
signature: {
hash: Binary.createFromBase64('3h7qyhLsgU21Pnzf/KVLl8suu2I=', 0),
keyId: Long('7449048397505364002')
}
},
operationTime: Timestamp({ t: 1749235753, i: 31 })
}

nNonCompliantDocuments: 0 in the output indicates that all the documents in the accounts collection comply with the collection schemas.输出中的nNonCompliantDocuments: 0表示帐户集合中的所有文档都符合集合架构。

5

Test your schema validation测试模式验证

To verify your schema validation, you can try to insert an invalid document into the accounts collection. For example, try inserting a customer document missing the required last field, for last name:为了验证架构验证,您可以尝试将无效文档插入到accounts集合中。例如,尝试插入一个缺少姓氏所需的last字段的customer文档:

db.accounts.insertOne(
{
"docType": "customer",
"customerId": "12345",
"name": {
"first": "John",
},
"customerSince": "2025-01-01T00:00:00Z"
}
)
MongoServerError: Document failed validation