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 schema 文档始终从其根节点描述整个文档。模式本身是一个模式对象,可以包含描述属性和子文档的嵌入式模式对象。 |
2 | required 是一个属性,描述了文档中哪些属性是必需的。它可以是可选的,与其它模式约束一起指定。请参阅 MongoDB 文档中关于可用关键字的说明。 |
3 | properties 与描述 object 类型的模式对象相关。它包含属性特定的模式约束。 |
4 | firstname 指定了文档中 firstname 字段的约束。这里,它是一个基于字符串的 properties 元素,声明了可能的字段值。 |
5 | address 是一个子文档,为其 postCode 字段中的值定义了模式。 |
您可以通过指定模式文档(即使用 Document
API 解析或构建文档对象)或使用 Spring Data 在 org.springframework.data.mongodb.core.schema
包中的 JSON schema 工具来提供模式。MongoJsonSchema
是所有 JSON schema 相关操作的入口点。以下示例展示了如何使用 MongoJsonSchema.builder()
创建 JSON schema:
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 | 配置必需的 String 类型字段 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));
生成 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 | 由转换器转换为 Code 的 String 类型属性。 |
6 | 生成模式时会忽略 @Transient 属性。 |
使用可转换为 ObjectId 的类型的 _id 属性(例如 String )会被映射为 { type : 'object' } ,除非通过 @MongoId 注解提供了更具体的信息。 |
Java | Schema 类型 | 备注 |
---|---|---|
|
|
如果元数据可用,带 |
|
|
- |
|
|
- |
|
|
带包含可能的枚举值的 |
|
|
简单类型数组,除非它是 |
|
|
- |
上述示例展示了如何从精确类型化的源派生模式。在域模型中使用多态元素可能会导致 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 schema 才能合并。以下示例显示了一个由于数据类型不匹配而无法自动合并的定义。在这种情况下,必须向
|
加密字段
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 类型
Schema 类型 | Java 类型 | Schema 属性 |
---|---|---|
|
- |
|
|
|
|
|
除 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
|
|
(无) |
untyped 是一种通用类型,所有类型化模式类型都继承自它。它向类型化模式类型提供了所有 untyped 模式属性。 |
更多信息请参阅 $jsonSchema。