是否有一种方法可以在嵌套JSON模式中实现与CHECK约束等效的Postgres?假设我们有两个属性的数据,每个属性都有嵌套的属性。 JSON Schema如何使第一个对象的必需内容取决于第二个对象?
我的实际情况是为GeoJSON对象构建一个JSON模式,该对象具有一个几何对象(即Point或Polygon或null)以及“ properties”对象中的其他属性。我想根据几何类型更改所需的属性。
我无法通过以下两种解决方案:
这将验证,因为属性/位置涵盖了缺少几何图形的情况:
{
"attributes": {
"name": "Person2",
"place": "City2"
},
"geometry": null
}
这也将验证,因为几何不再需要属性/位置:
{
"attributes": {
"name": "Person1"
},
"geometry": {
"type": "Point",
"coordinates": []
}
}
编辑
基于Relequestual的答案,这是我得到的令人满意的结果:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"type": "object",
"required": ["type"],
"properties": {
"type": {
"const": "Point"
}
}
},
"partialAttributes": {
"type": "object",
"required": ["name"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"fullAttributes": {
"type": "object",
"required": ["name", "place"],
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/partialAttributes"
},
"else": {
"$ref": "#/definitions/fullAttributes"
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/conditionalAttributes"
},
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
}
如果删除了attributes/place
属性,此架构将无法验证以下内容。
{
"attributes": {
"name": "Person",
"place": "INVALID IF THIS LINE IS REMOVED ;-("
},
"geometry": {
"type": "Point",
"coordinates": {}
}
}
答案 0 :(得分:0)
您可以使用if/then/else
keywords有条件地应用子计划。
我们只希望if
和then
为您提供解决方案。
两者的值都必须是JSON模式。
如果if
的值导致一个肯定的断言(将模式应用于实例并成功验证时),则将then
的模式值应用于实例。 / p>
这是架构。
我已经在https://jsonschema.dev处预加载了架构和数据,因此您可以对其进行实时测试。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometryIsPoint": {
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"geometryAsPoint": {
"required": [
"coordinates"
],
"properties": {
"coordinates": {
"type": "array"
}
}
},
"geometry": {
"allOf": [
{
"if": {
"$ref": "#/definitions/geometryIsPoint"
},
"then": {
"$ref": "#/definitions/geometryAsPoint"
}
}
]
}
},
"properties": {
"geometry": {
"$ref": "#/definitions/geometry"
}
}
}
属性geometry
引用了定义geometry
。
allOf
是一个模式数组。
allOf[0].if
的值引用了定义为geometryIsPoint
的架构。
定义为geometryIsPoint
的架构将应用于geometry
值。如果验证成功,则将应用then
引用的架构。
您不必使用引用来执行任何上述操作,但我认为这样做可以使意图更清晰。
根据需要扩展架构,将架构添加到allOf
中,以获取您想要识别的多种几何类型。
编辑:
由于else
验证失败,因此您达到了条件中的if
条件。让我解释一下。
这是一个更新的架构,涵盖了您修改过的用例。
{
"$schema": "http://json-schema.org/draft-07/schema#",
"definitions": {
"geometry": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"enum": [
"Point",
"somethingelse",
null
]
}
}
},
"geometryIsPoint": {
"type": "object",
"required": [
"type"
],
"properties": {
"type": {
"const": "Point"
}
}
},
"attributes": {
"properties": {
"name": {
"type": "string"
},
"place": {
"type": "string"
}
}
},
"partialAttributes": {
"type": "object",
"required": [
"name"
]
},
"fullAttributes": {
"type": "object",
"required": [
"name",
"place"
]
},
"conditionalAttributes": {
"allOf": [
{
"if": {
"required": [
"geometry"
],
"properties": {
"geometry": {
"$ref": "#/definitions/geometryIsPoint"
}
}
},
"then": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/partialAttributes"
}
}
},
"else": {
"required": [
"attributes"
],
"properties": {
"attributes": {
"$ref": "#/definitions/fullAttributes"
}
}
}
}
]
}
},
"properties": {
"attributes": {
"$ref": "#/definitions/attributes"
},
"geometry": {
"$ref": "#/definitions/geometry"
}
},
"allOf": [
{
"$ref": "#/definitions/conditionalAttributes"
}
]
}
这里是JSON Schema dev link,因此您可以对其进行测试。
我们在这里正在做的是分散关注点。
attributes
和geometry
的“形状”是在定义中使用相应的键定义的。这些架构没有断言那些对象中需要哪些键,只有提供它们时才必须断言。
由于架构中的$ref
会忽略架构中的所有其他关键字(对于草稿7或更低版本),因此在根级别,我将对conditionalAttributes
的引用包装在{{ 1}}。
allOf
是已定义的JSON模式。我使用过conditionalAttributes
,因此您可以添加更多条件检查。
allOf
的值是一个JSON模式,并应用于JSON实例的根。它需要密钥conditionalAttributes.allOf[0].if
,并且值为geometry
。 (如果省略geometryIsPoint
,则会遇到验证问题,因为省略该键将通过if条件。)
当实例为required
值架构产生true
断言(验证有效)时,则在根级别应用if
值架构。
因为它是在根级别应用的,并且您要检查嵌套属性的值,所以必须使用then
,就像在架构的根级别一样。 这是您如何在实例的不同深度进行条件模式应用程序(properties
)。
您可以通过将模式值之一更改为if/then/else
并查看错误来测试条件解析。请记住,false
和true
是有效的JSON模式,因此,如果您希望应用false
模式(例如,{ {1}}模式断言验证成功)。