JSON Schema
从版本 3.6 开始,MongoDB 支持根据提供的 JSON Schema验证文档的集合。创建集合时可以定义架构本身以及验证操作和级别,如下例所示: .Sample 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 关于 available keywords的文档。 |
3 | properties 与一个描述 object 类型的模式对象相关。它包含特定于属性的模式约束。 |
4 | firstname 指定文档中 firstname 字段的约束。在此,它是一个基于字符串的 properties 元素,声明可能的字段值。 |
5 | address 是一个子文档,它为其 postCode 字段中的值定义一个模式。 |
您可以通过指定模式文档(即使用 Document
API 解析或构建文档对象)或使用 Spring Data 的 org.springframework.data.mongodb.core.schema
中的 JSON 模式实用程序来构建模式来提供此模式。MongoJsonSchema
是所有 JSON 模式相关操作的入口点。以下示例显示了如何使用 MongoJsonSchema.builder()
创建 JSON 模式:
.Creating a 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 | Build the schema object. |
网关接口上的静态方法中已经提供了一些预定义且强类型的模式对象(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
为集合的模式支持提供了入口点,如下例所示:
.Create collection with $jsonSchema
MongoJsonSchema schema = MongoJsonSchema.builder().required("firstname", "lastname").build();
template.createCollection(Person.class, CollectionOptions.empty().schema(schema));
Generating a Schema
设置模式可能是一项耗时的任务,我们鼓励每个人在决定这样做时真正花时间去完成。请务必注意,模式更改可能很困难。不过,有时人们可能不想因此而退缩,这就是 JsonSchemaCreator
发挥作用的地方。
JsonSchemaCreator`及其默认实现是从映射基础结构提供的域类型元数据中生成 `MongoJsonSchema
。这意味着,会考虑 annotated properties以及潜在的 custom conversions。
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 属性。 |
|
Java | Schema Type | Notes |
---|---|---|
|
|
如果元数据可用,则使用 |
|
|
- |
|
|
- |
|
|
具有保存可能的枚举值的属性的 |
|
|
简单类型数组,除非是 |
|
|
- |
上面的示例演示了如何从非常精确的类型化来源派生模式。在域模型中使用多态元素可能会导致 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 架构。以下示例显示一个定义,该定义无法自动合并,因为数据类型不匹配。在这种情况下,必须向
|
Encrypted Fields
MongoDB 4.2 Field Level Encryption允许直接加密各个属性。
在设置 JSON 架构时,可以在加密属性中包装属性,如下面的示例所示。
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 Types
下表显示了受支持的 JSON 架构类型:
Schema Type | Java Type | Schema Properties |
---|---|---|
|
- |
|
|
|
|
|
any array except |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
|
(none) |
|
有关更多信息,请参阅 $jsonSchema。