JSON Schema
从 3.6 版本开始,MongoDB 支持根据提供的 JSON Schema 验证文档的集合。在创建集合时,可以定义模式本身以及验证操作和级别,如下例所示
{
"type": "object", (1)
"required": [ "firstname", "lastname" ], (2)
"properties": { (3)
"firstname": { (4)
"type": "string",
"enum": [ "luke", "han" ]
},
"address": { (5)
"type": "object",
"properties": {
"postCode": { "type": "string", "minLength": 4, "maxLength": 5 }
}
}
}
}
1 | JSON 架构文档始终描述从根开始的整个文档。架构本身就是一个架构对象,它可以包含描述属性和子文档的嵌入式架构对象。 |
2 | required 是一个属性,它描述了文档中哪些属性是必需的。它可以与其他架构约束一起可选地指定。有关详细信息,请参阅 MongoDB 的文档,了解可用关键字。 |
3 | properties 与描述 object 类型的架构对象相关。它包含特定于属性的架构约束。 |
4 | firstname 指定文档中 firstname 字段的约束。在这里,它是一个基于字符串的 properties 元素,声明了可能的字段值。 |
5 | address 是一个子文档,定义了其 postCode 字段中值的架构。 |
您可以通过指定架构文档(即使用 Document
API 解析或构建文档对象)或使用 Spring Data 的 JSON 架构实用程序(位于 org.springframework.data.mongodb.core.schema
中)来构建架构。MongoJsonSchema
是所有 JSON 架构相关操作的入口点。以下示例展示了如何使用 MongoJsonSchema.builder()
创建 JSON 架构
MongoJsonSchema.builder() (1)
.required("lastname") (2)
.properties(
required(string("firstname").possibleValues("luke", "han")), (3)
object("address")
.properties(string("postCode").minLength(4).maxLength(5)))
.build(); (4)
1 | 获取架构构建器,使用流畅的 API 配置架构。 |
2 | 直接配置必需属性,如这里所示,或使用更多详细信息,如 3 中所示。 |
3 | 配置必需的字符串类型 firstname 字段,仅允许 luke 和 han 值。属性可以是类型化的或非类型化的。使用 JsonSchemaProperty 的静态导入使语法更紧凑,并获取入口点,例如 string(…) 。 |
4 | 构建架构对象。 |
通过网关接口上的静态方法,已经有一些预定义的和强类型化的架构对象(JsonSchemaObject
和 JsonSchemaProperty
)可用。但是,您可能需要构建自定义属性验证规则,这些规则可以通过构建器 API 创建,如下面的示例所示
// "birthdate" : { "bsonType": "date" }
JsonSchemaProperty.named("birthdate").ofType(Type.dateType());
// "birthdate" : { "bsonType": "date", "description", "Must be a date" }
JsonSchemaProperty.named("birthdate").with(JsonSchemaObject.of(Type.dateType()).description("Must be a date"));
CollectionOptions
提供了对集合架构支持的入口点,如下面的示例所示
$jsonSchema
创建集合MongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();
template.createCollection(Person.class, CollectionOptions.empty().schema(schema));
生成架构
设置架构可能是一项耗时的任务,我们鼓励所有决定这样做的人,真正花时间去做。重要的是,架构更改可能很困难。但是,可能会有时候人们不想被它困扰,这就是 JsonSchemaCreator
发挥作用的地方。
public class Person {
private final String firstname; (1)
private final int age; (2)
private Species species; (3)
private Address address; (4)
private @Field(fieldType=SCRIPT) String theForce; (5)
private @Transient Boolean useTheForce; (6)
public Person(String firstname, int age) { (1) (2)
this.firstname = firstname;
this.age = age;
}
// gettter / setter omitted
}
MongoJsonSchema schema = MongoJsonSchemaCreator.create(mongoOperations.getConverter())
.createSchemaFor(Person.class);
template.createCollection(Person.class, CollectionOptions.empty().schema(schema));
{
'type' : 'object',
'required' : ['age'], (2)
'properties' : {
'firstname' : { 'type' : 'string' }, (1)
'age' : { 'bsonType' : 'int' } (2)
'species' : { (3)
'type' : 'string',
'enum' : ['HUMAN', 'WOOKIE', 'UNKNOWN']
}
'address' : { (4)
'type' : 'object'
'properties' : {
'postCode' : { 'type': 'string' }
}
},
'theForce' : { 'type' : 'javascript'} (5)
}
}
1 | 简单对象属性被视为常规属性。 |
2 | 原始类型被视为必需属性 |
3 | 枚举被限制为可能的值。 |
4 | 对象类型属性被检查并表示为嵌套文档。 |
5 | String 类型属性,由转换器转换为 Code 。 |
6 | @Transient 属性在生成模式时被省略。 |
使用可以转换为 ObjectId 的类型的 _id 属性(如 String )被映射到 { type : 'object' } ,除非通过 @MongoId 注解提供更具体的的信息。
|
Java | 模式类型 | 备注 |
---|---|---|
|
|
如果元数据可用,则使用 |
|
|
- |
|
|
- |
|
|
使用 |
|
|
简单类型数组,除非它是 |
|
|
- |
上面的例子展示了如何从非常精确的类型化源代码中推导出模式。在域模型中使用多态元素会导致 Object
和泛型 <T>
类型的模式表示不准确,这些类型很可能被表示为 { type : 'object' }
,而没有进一步的说明。MongoJsonSchemaCreator.property(…)
允许定义额外的细节,例如在渲染模式时应该考虑的嵌套文档类型。
class Root {
Object value;
}
class A {
String aValue;
}
class B {
String bValue;
}
MongoJsonSchemaCreator.create()
.property("value").withTypes(A.class, B.class) (1)
{
'type' : 'object',
'properties' : {
'value' : {
'type' : 'object',
'properties' : { (1)
'aValue' : { 'type' : 'string' },
'bValue' : { 'type' : 'string' }
}
}
}
}
1 | 给定类型的属性合并到一个元素中。 |
MongoDB 的无模式方法允许在同一个集合中存储不同结构的文档。这些文档可能被建模为具有一个共同的基类。无论选择哪种方法,MongoJsonSchemaCreator.merge(…)
都可以帮助避免将多个模式合并为一个的需要。
abstract class Root {
String rootValue;
}
class A extends Root {
String aValue;
}
class B extends Root {
String bValue;
}
MongoJsonSchemaCreator.mergedSchemaFor(A.class, B.class) (1)
{
'type' : 'object',
'properties' : { (1)
'rootValue' : { 'type' : 'string' },
'aValue' : { 'type' : 'string' },
'bValue' : { 'type' : 'string' }
}
}
}
1 | 给定类型的属性(及其继承的属性)被组合成一个模式。 |
具有相同名称的属性需要引用相同的 JSON 模式才能被组合。以下示例展示了一个无法自动合并的定义,因为数据类型不匹配。在这种情况下,必须向
|
加密字段
MongoDB 4.2 字段级加密 允许直接加密单个属性。
在设置 JSON Schema 时,可以将属性包装在加密属性中,如下面的示例所示。
MongoJsonSchema schema = MongoJsonSchema.builder()
.properties(
encrypted(string("ssn"))
.algorithm("AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic")
.keyId("*key0_id")
).build();
无需手动定义加密字段,可以使用 @Encrypted
注解,如下面的代码片段所示。
@Document
@Encrypted(keyId = "xKVup8B1Q+CkHaVRx+qa+g==", algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Random") (1)
static class Patient {
@Id String id;
String name;
@Encrypted (2)
String bloodType;
@Encrypted(algorithm = "AEAD_AES_256_CBC_HMAC_SHA_512-Deterministic") (3)
Integer ssn;
}
1 | 将为 encryptMetadata 设置的默认加密设置。 |
2 | 使用默认加密设置的加密字段。 |
3 | 覆盖默认加密算法的加密字段。 |
|
JSON Schema 类型
下表显示了支持的 JSON Schema 类型
模式类型 | Java 类型 | Schema 属性 |
---|---|---|
|
- |
|
|
|
|
|
除 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
untyped 是一种通用类型,所有类型化的模式类型都继承自它。它为类型化的模式类型提供所有 untyped 模式属性。
|
有关更多信息,请参阅 $jsonSchema。