Using Jsonschema draft 6, I'm trying to create a schema that conforms to the following:
Properties A, B1, B2, and B3 are either numbers or null
If property A is present and non-null, then properties B1, B2, and B3 must be either absent or null
If any of properties B1, B2, and B3 are present and non-null, then property A must be null or absent.
A, B1, B2, and B3 may all be absent
Examples of conforming documents:
{}
{"A": 1}
{"A": 1, "B2": null}
{"B1": 1}
{"B1": 1, "B2": 1, "B3": 1}
{"A": null, "B1": 1, "B2": 1, "B3": 1}
Examples of non-conforming documents:
{"A": 1, "B1": 2}
{"A": 1, "B1": null, "B2": 1}
I've seen some related questions that help but don't fully answer the question:
How to make anyOf a set of mutually exclusive properties except one
Use json-schema to require or disallow properties based on another property value?
jsonSchema attribute conditionally required
How to define choice element in json schema when elements are optional?
How to define a JSON schema that requires at least one of many properties
Here is my current schema, which only enforces constraint #1 and #4:
{
"$schema": "http://json-schema.org/draft-06/schema#",
"properties": {
"A": {"oneOf": [{"type": "null"}, {"type": "number"}],
"B1": {"oneOf": [{"type": "null"}, {"type": "number"}],
"B2": {"oneOf": [{"type": "null"}, {"type": "number"}],
"B3": {"oneOf": [{"type": "null"}, {"type": "number"}]
}
}
What is the right approach here? Am I asking for something unreasonable?
{
"$schema": "http://json-schema.org/draft-06/schema#",
"oneOf": [
{
"properties": {
"A": {"type": "number"},
"B1": {"type": "null"},
"B2": {"type": "null"},
"B3": {"type": "null"}
},
"required": ["A"]
},
{
"properties": {
"A": {"type": "null"},
"B1": {"type": ["number","null"]},
"B2": {"type": ["number","null"]},
"B3": {"type": ["number","null"]}
},
"anyOf": [
{"required": ["B1"]},
{"required": ["B2"]},
{"required": ["B3"]}
]
},
{
"properties": {
"A": {"type": "null"},
"B1": {"type": "null"},
"B2": {"type": "null"},
"B3": {"type": "null"}
}
}
]
}
Related
I am trying to understand Avro schemas and stuck with complex types (record). The problem is very simple: create a schema which contains one record filed with two primitive fields (string and timestamp) nested to record. I see two options for the schema:
option 1
{
"type": "record",
"name": "cool_subject",
"namespace": "com.example",
"fields": [
{
"name": "field_1",
"type": "record"
"fields": [
{"name": "operation", "type": "string"},
{"name": "timestamp", "type": "long", "logical_type": "timestamp_millis"}
]
}
]
}
option 2
{
"type": "record",
"name": "cool_subject",
"namespace": "com.example",
"fields": [
{
"name": "field_1",
"type": {
"type": "record",
"name": "field_1_type",
"fields": [
{"name": "operation", "type": "string"},
{"name": "timestamp", "type": {"type": "long", "logical_type": "timestamp_millis"}}
]
}
}
]
}
The difference is in the "type" attribute.
As far as I know opt2 is the correct way. Am I right? Is opt1 valid?
The second one is correct. The first one is not valid.
A record schema is something that looks like this:
{
"type": "record",
"name": <Name of the record>,
"fields": [...],
}
And for fields, it should be like this:
[
{
"name": <name of field>,
"type": <type of field>,
},
...
]
So in the case of a field which contains a record, it should always look like this:
[
{
"name": <name of field>,
"type": {
"type": "record",
"name": <Name of the record>,
"fields": [...],
}
},
...
]
The format in the first example would make it unclear if the name "field_1" was the name of the field or the name of the record.
I want to validate a JSON file using JSON schema, several "properties" should be required depending on what values some other properties have.
Example
Having properties "A", "B", "C", and "D"
if "A" has value "foo", C is required
if "B" has value "foo", D is required
if both "A" and "B" each have value "foo", both C and D are required
else, nothing is required
I have seen a very helpful answer here: https://stackoverflow.com/a/38781027/5201771 --> there, the author addresses how to solve this problem for the case of a single property (e.g., only "A" has value "foo", so require "C").
However, I currently don't see how to extend that answer to my case, where several properties determine the outcome.
Example Files
for illustration, I supply some files that should pass or fail the validation:
should pass:
{
"A": "bar"
"B": "baz"
}
{
"A": "foo"
"C": "some value"
}
{
"A": "bar"
"B": "foo"
"D": "some value"
}
should fail:
{
"A": "foo"
"B": "foo"
"D": "some value"
}
You can combine conditionals a number of ways, but combining them with allOf is usually the best way.
{
"type": "object",
"properties": {
"A": {},
"B": {},
"C": {},
"D": {}
},
"allOf": [
{ "$ref": "#/definitions/if-A-then-C-is-required" },
{ "$ref": "#/definitions/if-B-then-D-is-required" }
],
"definitions": {
"if-A-then-C-is-required": {
"if": {
"type": "object",
"properties": {
"A": { "const": "foo" }
},
"required": ["A"]
},
"then": { "required": ["C"] }
},
"if-B-then-D-is-required": {
"if": {
"type": "object",
"properties": {
"B": { "const": "foo" }
},
"required": ["B"]
},
"then": { "required": ["D"] }
}
}
}
We have a jsonb column with data of the type:
"basket": {
"total": 6,
"items": [
{ "type": "A", "name": "A", "price": 1 },
{ "type": "A", "name": "B", "price": 2 },
{ "type": "C", "name": "C", "price": 3 },
]
}
We need to construct few queries that will filter specific elements of the items[] array for SELECT and SUM.
We have PG v9.6 so using jsonb_path_query_array didn't work.
Using basket->'items' #> '{"type":"A"}' works to find all entries that has type-A.
But how do we get subquery to
select only basket items of type-A
sum of prices of items of type-A
Thank you!
This will select the required items:
select * from jsonb_array_elements('{"basket":
{
"total": 6,
"items": [
{ "type": "A", "name": "A", "price": 1 },
{ "type": "A", "name": "B", "price": 2 },
{ "type": "C", "name": "C", "price": 3 }
]
}}'::jsonb#>'{basket,items}') e(it)
where it->>'type' = 'A';
and this the sum of prices:
select sum(cast(it->>'price' as numeric)) from jsonb_array_elements('{"basket":
{
"total": 6,
"items": [
{ "type": "A", "name": "A", "price": 1 },
{ "type": "A", "name": "B", "price": 2 },
{ "type": "C", "name": "C", "price": 3 }
]
}}'::jsonb#>'{basket,items}') e(it)
where it->>'type' = 'A';
I have the following JSON snippets which are all valid
"units": { "name": "EU", "value": "Grams" }
"units": { "name": "EU", "value": "Kilograms" }
"units": { "name": "US", "value": "Ounces" }
"units": { "name": "US", "value": "Pounds" }
The name values can be EU and US and the valid value value should depend on the name value.
It's easy to use JSON Schema enums for both these properties, but can I enforce the additional constraint using JSON Schema?
I would consider changing the overall schema so that there is a parent child relationship between a name object and value object, but ideally this would be avoided.
I managed to crack it using https://www.jsonschemavalidator.net/ to work though an example. The following schema provides the solution:
"units": {
"type":"object",
"oneOf": [ {
"properties": {
"name": { "enum": [ "EU" ] },
"value": { "enum" : ["Grams", "Kilograms"]}}}, {
"properties": {
"name": { "enum": [ "US" ] },
"value": { "enum": ["Ounces", "Pounds"]}}}]
}
I am trying to validate if the "actions" array has specific objects. Each object can have their own properties, depending on the type property. The actions array can have multiple occurences from these type of objects, not just one.
My JSON:
{
"actions": [
{
"type": "X",
"a": 1,
"b": 2,
"c": 3
},
{
"type": "Y",
"d": 1,
"e": 2,
"f": 3
}
]
}
In this example the object that has type = X has required properties as a, b, c. The object type Y in the array has required properties d, e, f.
I am trying to validate this with the switch keyword:
{
"type": "object",
"required": [
"actions"
],
"properties": {
"actions": {
"type": "array",
"items": {
"switch": [
{
"if": {
"properties": {
"type": {
"pattern": "^X$"
}
}
},
"then": {
"required": [
"a",
"b",
"c"
]
}
},
{
"if": {
"properties": {
"type": {
"pattern": "^Y$"
}
}
},
"then": {
"required": [
"d",
"e",
"f"
]
}
}
]
}
},
}
}
But still I could not figure out how to use the switch keyword to validate objects of arrays where each object type is specified by a property in the object so the object type can be identified with a property.
Your schema looks almost ok, you may need one last {then: false} subschema inside "switch", as without it if the "type" property is neither 'X' nor 'Y' the validation will succeed.
Also, instead of using {pattern: '^X$'} you can use {enum: ['X']} or even {constant: 'X'} (in draft-06 it is "const"); instead of using switch you can use "if/then/else" (from ajv-keywords, it is likely to be included in draft-07) or even "select", that may be more suitable for such scenario.
Maybe you can clarify the last question, I don't think I understand.