18

How can I check in the following json that at least one element in the array names has a property nickName with the value Ginny?

{
  "names": [
    {
      "firstName": "Hermione",
      "lastName": "Granger"
    }, {
      "firstName": "Harry",
      "lastName": "Potter"
    }, {
      "firstName": "Ron",
      "lastName": "Weasley"
    }, {
      "firstName": "Ginevra",
      "lastName": "Weasley",
      "nickName": "Ginny"
    }
  ]
}

Currently I'm using the draft-06 version (FAQ here).

This is my NOT WORKING schema:

{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "title": "Complex Array",
  "description": "Schema to validate the presence and value of an object within an array.",

  "type": "object",
  "properties": {
    "names": {
      "type": "array",
      "minItems": 1,
      "items": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "nickName": {
            "type": "string"
          }
        },
        "anyOf": [
          {"required": ["nickName"]}
        ]
      }
    }
  }
}
fpenim
  • 491
  • 1
  • 4
  • 14

2 Answers2

27

I managed to figure it out using draft-06. On this version a new keyword contains was added. According to this draft specification:

contains

The value of this keyword MUST be a valid JSON Schema. An array instance is valid against "contains" if at least one of its elements is valid against the given schema.

Working schema:

{
  "$schema": "http://json-schema.org/draft-06/schema#",
  "title": "Complex Array",

  "type": "object",
  "properties": {
    "names": {
      "type": "array",
      "minItems": 1,
      "contains": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "nickName": {
            "type": "string",
            "pattern": "^Ginny$"
          }
        },
        "required": ["nickName"]
      },
      "items": {
        "type": "object",
        "properties": {
          "firstName": {
            "type": "string"
          },
          "lastName": {
            "type": "string"
          },
          "nickName": {
            "type": "string"
          }
        }
      }
    }
  }
}
fpenim
  • 491
  • 1
  • 4
  • 14
2

The previous answer for draft-06 works, but if you are limited to use a previous JSON Schema draft who doesn't support the contains keyword (like the one supported by MongoDB), you can use a double negation trick:

{ "type": "object",
  "properties" : {
      "names" : {
          "allOf" : [
              {"type" : "array"},
              {"not" : {
                  "type" : "array",
                  "items" : { 
                      "not" : { 
                          "type" : "object",
                          "properties" : { 
                              "nickName" : { 
                                  "enum" : ["Ginny"]
                              }
                          },
                          "required" : ["nickName"]
                      }
                  }}
              }              
          ]} 
  }}
Nahuel Greco
  • 1,080
  • 14
  • 12