45

Given the following JSON schema, is it possible to indicate that the "name" property shall be unique (i.e. there should NOT be two items with the same "name" in the "elements" array.

{
  "root": {
    "type": "object",
    "properties": {
      "elements": {
        "type": "array",
        "minItems": 1,
        "items": {
          "type": "object",
          "properties": {
            "name": {
              "type": "string",
              "title": "Element Name",
              "minLength": 3,
            },
            "url": {
              "type": "string",
              "title": "Some URL"
            }
          }
        }
      }
    }
  }
}

I tried to use the uniqueItems keyword but it seems it was designed for simple lists of values.

KyleMit
  • 30,350
  • 66
  • 462
  • 664
begie
  • 1,194
  • 1
  • 11
  • 23
  • I guess it was by specifying `"uniqueItems": true`. Never used it before http://json-schema.org/example1.html EDIT: ietf definition: http://tools.ietf.org/html/draft-fge-json-schema-validation-00#section-5.3.4 – luchosrock Jul 15 '14 at 16:50
  • 1
    Problem is 5.3.4.2. Conditions for successful validation says: "the instance validates successfully if all of its elements are unique.". But how do you define if elements are unique or not? – begie Jul 15 '14 at 16:59
  • 1
    Also, you may be interested in https://github.com/json-schema-org/json-schema-spec/issues/538 – gregsdennis Sep 29 '19 at 20:08

4 Answers4

37

No, it is not possible. From the docs, json-schema: ...a JSON based format for defining the structure of JSON data.

It is quite limited for making data values validation because it is not the purpose of the standard. Many people have asked this before because it is common to request a kind of "unique Id" feature. Unfortunately for those who need it, json-schema does not provides you with that.

So if you want to ensure uniqueness your only option is to have "name" as property keys instead of property values.

jruizaranguren
  • 12,679
  • 7
  • 55
  • 73
  • 2
    Thanks. Indeed this is not possible with current JSON Schema standard. There is a discussion whether this feature shall be included in one of future versions of the standard: https://groups.google.com/forum/?hl=en#!topic/json-schema/CYd8xk1Czyg – begie Jul 29 '14 at 08:13
  • It seems to be possible now, referring to the docs: https://spacetelescope.github.io/understanding-json-schema/reference/array.html#uniqueness – dude Sep 13 '17 at 09:45
  • 5
    @dude, it still isnot possible. The question was asking for enforcing uniqueness in property values. Uniqueness in arrays that you link was available in previous versions of the standard. – jruizaranguren Sep 13 '17 at 16:18
14

If refactoring the data structure is an option, the following approach may be helpful:

  • Replace the array by a map. This can easily be achieved by using an object with patternProperties. The pattern is a regular expression. Any object that matches the pattern will be validated against the schema of the pattern-property. A pattern matching any string >= 3 characters looks like this: "....*", but it seems that a trailing ".*" is always implied, so "..." works as well.
  • Adding additionalProperties:false is an additional step to enforce your constraint (minLength:3).
  • To enforce at least one element in your map (you were using minItems:1 for your array), replace minItems by minProperties.

... resulting in the schema below:

"root": {
  "type": "object", 
  "properties": {
    "elements": {
      "type": "object", 
      "patternProperties": {
        "...": {
          "type": "object", 
          "properties": {
            "url": {
              "type": "string"
            }
          }
        }
      }, 
      "additionalProperties": false, 
      "minProperties": 1
    }
  }
}

If a document like the following (excerpt) was matching your old schema,

"elements": [
  {
    "name": "abc", 
    "url": "http://myurl1"
  }, 
  {
    "name": "def", 
    "url": "http://myurl2"
  }, 
  {
    "name": "ghij", 
    "url": "http://myurlx"
  }
]

... a document like that (excerpt) will match the new schema:

"elements": {
  "abc": {
    "url": "http://myurl1"
  }, 
  "def": {
    "url": "http://myurl2"
  }, 
  "ghij": {
    "url": "http://myurlx"
  }
}
yaccob
  • 1,230
  • 13
  • 16
  • 3
    But this doesn't check if an element inside an object is really unique – dude Sep 13 '17 at 09:41
  • Well, unfortunately the JSON specification recommends but doesn't enforce uniqueness on keys (https://tools.ietf.org/html/rfc7159#section-4). Nevertheless some parsers do enforce uniqueness. – yaccob Sep 14 '17 at 10:35
  • 1
    @yaccob that's the point of JSON-Schema to enforce things which aren't enforceable by JSON – citizen conn Nov 14 '18 at 14:20
  • @citizenconn I understand what you're saying but to me it's not obvious why you're saying it. Can you please explain? – yaccob Nov 15 '18 at 20:02
  • 1
    @yaccob honestly man I don't remember and I lost context, sorry! – citizen conn Dec 03 '18 at 22:09
3

For Ajv validator you can use custom JSON-Schema keyword uniqueItemProperties : ajv-validator/ajv-keywords

1

If your use-case can handle the added overhead, you can apply a transformation on the document to generate a reduced document, and then apply validation again with a separate mini schema on the reduced document.

Here are some links with information on Json transformation tools:

Handling your example case would be very straightforward in JSONata.

Basel Shishani
  • 7,735
  • 6
  • 50
  • 67