|
此版本仍在开发中,尚未被视为稳定版。如需最新稳定版本,请使用 Spring Data MongoDB 5.0.4! |
JSON Schema
从 3.6 版本开始,MongoDB 支持在集合中根据提供的 JSON Schema 对文档进行验证。 如下例所示,该 schema 本身以及验证操作(validation action)和验证级别(validation level)均可在创建集合时定义:
{
"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 是一个属性,用于描述文档中哪些属性是必需的。它可以与其他 schema 约束一起可选地指定。请参阅 MongoDB 关于可用关键字的文档。 |
| 3 | properties 与描述 object 类型的模式对象相关。它包含特定于属性的模式约束。 |
| 4 | firstname 用于指定文档中 firstname 字段的约束条件。此处,它是一个基于字符串的 properties 元素,用于声明该字段可能的取值。 |
| 5 | address 是一个子文档,用于为其 postCode 字段中的值定义模式。 |
你可以通过指定一个 schema 文档(即使用 Document API 来解析或构建一个文档对象),或者使用 Spring Data 在 org.springframework.data.mongodb.core.schema 包中提供的 JSON schema 工具来构建 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 | 配置必需的字符串类型 firstname 字段,仅允许 luke 和 han 这两个值。属性可以是有类型的,也可以是无类型的。使用 JsonSchemaProperty 的静态导入可使语法更简洁,并提供诸如 string(…) 之类的入口点。 |
| 4 | 构建 schema 对象。 |
网关接口的静态方法已经提供了一些预定义且强类型的 Schema 对象(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 可能是一项耗时的工作,我们鼓励每一位决定进行此操作的人务必投入充足的时间。
这一点非常重要,因为 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 属性在生成数据库模式时会被忽略。 |
使用可转换为 _id 的类型(例如 ObjectId)的 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 的无模式(schema-free)方法允许将结构不同的文档存储在同一个集合中。
这些文档可以建模为拥有一个共同的基类。
无论采用哪种方法,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 架构类型
下表列出了支持的 JSON Schema 类型:
| 模式类型 | Java 类型 | 架构属性 |
|---|---|---|
|
- |
|
|
|
|
|
除 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
untyped 是一个泛型类型,所有带类型的 schema 类型都继承自它。它将所有 untyped schema 属性提供给带类型的 schema 类型。 |
有关更多信息,请参阅 $jsonSchema。