You have defined your schema correctly, except that it doesn't match the data you say you are validating. If you change the property names to match the schema, you still have one issue. If you want to allow "toll" and "message" to be null, you can do the following.
{
"type": "array",
"items": {
"type": "object",
"properties": {
"loc": {
"type": "string"
},
"toll": {
"type": ["string", "null"]
},
"message": {
"type": ["string", "null"]
}
},
"required": [
"loc"
]
}
}
However, that isn't related to the error message you are getting. That message means that data you are validating is not an array. The example data you posted should not result in this error. Are you running the validator on some data other than what is posted in the question?
Answer from Jason Desrosiers on Stack OverflowList of objects with required values
Contains not working as expected with array of objects
jsonschema - How can a json schema represent an array with different objects? - Stack Overflow
JSON Schema: How to require a value to be one of another properties array values
Videos
Does the second schema correctly identify that "arr is an array of objects that have an integer named type an integer, and either an object named Steps or an object named Heartrate"?
Yes, somewhat. You do not state which properties must exist, and which properties cannot exist together at the same time, which we can do with the "required" and "oneOf" keywords.
Here's an updated schema, and also fixing an error you made in the "Heartrate" section (you said "steps" instead of "heartrates"):
Copy{
"$schema": "https://json-schema.org/draft/2019-09/schema",
"type": "object",
"properties": {
"arr": {
"type": "array",
"items": {
"type": "object",
"required": [ "type" ],
"oneOf": [
{ "required": ["Steps"] },
{ "required": ["HeartRate"] }
},
"properties": {
"type": {
"type": "integer"
},
"Steps": {
"type": "object",
"required": ["steps"],
"properties": {
"steps": {
"type": "integer"
}
}
},
"HeartRate": {
"type": "object",
"required": ["heartrates"],
"properties": {
"heartrates": {
"type": "integer"
}
}
}
}
}
}
}
}
Well, it passes because technically it is valid, you can have any combination of objects in an array. This schema explicitly states that there can be a heartrate object. You say you're familiar with arrays of a single object type, but what you should know is an array doesn't care what types of objects are in it, which is why your introduced schema is in fact valid. Whether or not it fits the function you're trying to achieve is another question all together.
It would imply that you would need either one very complex loop to traverse the array when you need to pull an object, assuming there will be so many that you can't adequately index them, or you would need some sort of index with address to the objects in the array, which might be cumbersome to write but possible. So the question is, what are you intending to do with these objects? Seems obvious from the properties you're using, seems like a fitness monitor of some sort, but then what your intention to do with the data isn't apparent so it's difficult to say what you could do even if this schema is valid, which keep in mind that it is indeed a valid structure for an array.
Although if you do have two types of objects, one could ask why not simply have an array for each type which will have supporting data pulling functions specific to their contents. But again it asks what you're intending to do.
Hope this helps your thought process.
UPDATE...
Not knowing exactly what you are intending to do, here is what I suggest you use as your data-structure format.
Copylet someArray = [
{
Steps: {
steps: 3500
},
HeartRate: {
heartrates: 4000
}
},
{
Steps: {
steps: 3500
},
HeartRate: {
heartrates: 4000
}
}
]
You examples have some redundancy in them it seems, where they are explicitly stating that something is an object and something is a property of that object. JavaScript already knows all that so no need to add more complexity to the functions you create to work with these that will then have to dig through all those layers. I suggest that you create one object and each has a property of the type you've declared that is an object and that object can if you want be expanded or condensed as you desire. This will mitigate a lot of complexity to your structure. And so you'll see that you have an Array of Objects and those objects contain properties representing the data you're intending to gather.
But this assumes that the data you're gathering is from multiple sources. Again would need to know a bit more about what you're trying to accomplish.
So, I'm struggling to figure out how to word this, so apologies if this is confusing/unclear.
I have a (simplified) schema like so:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "fields/checkbox-multiple.json",
"title": "...",
"description": "...",
"type": "object",
"required": ["choices"],
"properties": {
"default": {
"description": "Default value of the field (optional)"
},
"choices": {
"description": "Choices for any type which has a multiple settings e.g. checkbox, radio, select etc",
"type": "array",
"minItems": 1,
"items": {
"required": ["value", "text"],
"properties": {
"value": {
"description": "Value to be used in the field. This will be the setting value e.g. true, false for a radio field"
},
"text": {
"description": "Text displayed on the field in the Customizer",
"type": "string"
}
}
}
}
}
}So the schema essentially creates a HTML Select field.
choices.value is the value of option tag, choices.text is the displayed text, fairly straight forward.
The default, is simply what the value of the input should be by default (again, sorry for stating the obvious).
Here's some React psuedo-code to make this clearer:
<select name="...">
{props.choices.map((choice) => {
return (props.default === props.value)
? <option value={choice.value} selected>{choice.text}</option>
: <option value={choices.value}>{choice.text}</option>
});
</select>Get to the question already!
So you may have already gotten it...The value of default MUST BE one of the choices.value ...errr...values.
Something like this in my head, but Googling is giving me everything but what I'm looking for...
{
"default": {
"enum": {
"oneOf": #choices.values.items.value
}
}
}Also, default is not required, but if it is given it has to be one of the choices.
Hope that makes sense! Thank in advance
You can achieve this using the anyOf keyword and definitions/$ref to avoid duplication.
{
"$schema": "http://json-schema.org/draft-07/schema#",
"type": "object",
"properties": {
"assetMetadata": {
"anyOf": [
{ "$ref": "#/definitions/assetMetaData" },
{
"type": "array",
"description": "...",
"items": { "$ref": "#/definitions/assetMetaData" }
}
]
}
},
"definitions": {
"assetMetadata": {
"type": "object",
"additionalProperties": false,
"properties": { ... }
}
}
}
The accepted answer was not working for me in the JSON schema validator.
The arrays were not being accepted.
I made some tweaks and changes to make it work, here is an example schema:
{
"$schema": "http://json-schema.org/draft-07/schema#",
"anyOf": [
{
"$ref": "#/definitions/commentObject"
},
{
"type": "array",
"description": "Array of Comment objects",
"items": {
"$ref": "#/definitions/commentObject"
}
}
],
"definitions": {
"commentObject": {
"properties": {
"number": {
"type": "integer",
"minLength": 0,
"maxLength": 256
},
"comment": {
"type": "string",
"minLength": 0,
"maxLength": 256
}
},
"required": [
"number",
"comment"
],
"type": "object"
}
}
}
Object used to test the validation:
{
"number": 47,
"comment": "This is a comment",
}
Arrays of objects used to test the validation:
[
{
"number": 47,
"comment": "This is a comment"
},
{
"number": 11,
"comment": "This is other comment"
}
]
JSON Schema Validator for object
JSON Schema Validator for array (of the same objects)
I got it to work using this validator by nesting the part of the schema for the array elements inside a object with the name items. The schema now has two nested items fields, but that is because one is a keyword in JSONSchema and the other because your JSON actually has a field called items
JSONSchema:
{
"type":"object",
"properties":{
"items":{
"type":"array",
"items":{
"properties":{
"item_id":{
"type":"number"
},
"quantity":{
"type":"number"
},
"price":{
"type":"number"
},
"title":{
"type":"string"
},
"description":{
"type":"string"
}
},
"required":[
"item_id",
"quantity",
"price",
"title",
"description"
],
"additionalProperties":false
}
}
}
}
JSON:
{
"items":[
{
"item_id":1,
"quantity":3,
"price":30,
"title":"item1 new name"
},
{
"item_id":1,
"quantity":16,
"price":30,
"title":"Test Two"
}
]
}
Output with two errors about missing description fields:
[ {
"level" : "error",
"schema" : {
"loadingURI" : "#",
"pointer" : "/properties/items/items"
},
"instance" : {
"pointer" : "/items/0"
},
"domain" : "validation",
"keyword" : "required",
"message" : "missing required property(ies)",
"required" : [ "description", "item_id", "price", "quantity", "title" ],
"missing" : [ "description" ]
}, {
"level" : "error",
"schema" : {
"loadingURI" : "#",
"pointer" : "/properties/items/items"
},
"instance" : {
"pointer" : "/items/1"
},
"domain" : "validation",
"keyword" : "required",
"message" : "missing required property(ies)",
"required" : [ "description", "item_id", "price", "quantity", "title" ],
"missing" : [ "description" ]
} ]
Try pasting the above into here to see the same output generated.
I realize this is an old thread, but since this question is linked from jsonschema.net, I thought it might be worth chiming in...
The problem with your original example is that you're declaring "properties" for an "array" type, rather than declaring "items" for the array, and then declaring an "object" type (with "properties") that populates the array. Here's a revised version of the original schema snippet:
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"item_id": {"type" : "number"},
"quantity": {"type": "number"},
"price": {"type" : "decimal"},
"title": {"type": "string"},
"description": {"type": "string"}
},
"required": ["item_id","quantity","price","title","description"],
"additionalProperties" : false
}
}
I would recommend against using the term "items" for the name of the array, to avoid confusion, but there's nothing stopping you from doing that...