After some initial exploration in the previous blog, more aspects on MongoDB’s $jsonschema are looked at in the following.
Example
First, let’s create a collection as follows. It is governed by a schema, and validation is in the strictest setting (the following is based on MongoDB version 3.6.0).
> mongo
> use more_exploration
> db.createCollection("orders", { "validator": { "$jsonSchema": { "bsonType": "object", "required": ["orderId", "orderDate", "orderLineItems"], "properties": { "orderId": { "bsonType": "int", "description": "Order Identifier: must be of type int and is required" }, "orderDate": { "bsonType": "date", "description": "Order Date: must be of type date and is required" }, "orderLineItems": { "bsonType": "array", "items": { "bsonType": "object", "properties": { "itemId": { "bsonType": "int" }, "numberOrdered": { "bsonType": "int" } } }, "description": "Order Line Items: must be of type array and is required" } } } }, "validationLevel": "strict", "validationAction": "error" })
{ "ok" : 1 }
The two documents from the example outlined in the initial blog of series are added next.
> db.orders.insert({ "orderId": NumberInt(1), "orderDate": new Date("2017-09-30"), "orderLineItems": [{ "itemId": NumberInt(55), "numberOrdered": NumberInt(20) }, { "itemId": NumberInt(56), "numberOrdered": NumberInt(21) } ] })
WriteResult({ "nInserted" : 1 })
> db.orders.insert({ "orderId": NumberInt(2), "orderDate": new Date("2017-09-30"), "orderLineItems": [{ "itemId": NumberInt(55), "numberOrdered": NumberInt(30) }, { "itemId": NumberInt(56), "numberOrdered": NumberInt(31) } ] })
WriteResult({ "nInserted" : 1 })
Insert Strictness and Partial Schema Coverage
The validator is in place on the collection “orders”. This can be verified with the command
> db.getCollectionInfos({name: "orders"})
Now let’s try and add a document that has additional properties in addition to those that comply with the schema as follows:
> db.orders.insert({ "orderId": NumberInt(3), "orderDate": new Date("2017-09-30"), "orderLineItems": [{ "itemId": NumberInt(55), "numberOrdered": NumberInt(40) }, { "itemId": NumberInt(56), "numberOrdered": NumberInt(41) } ], "preferredColor": "red" })
WriteResult({ "nInserted" : 1 })
It appears that as long as the schema is satisfied, additional properties can be inserted. So the schema is not completely covering the object to be inserted, but only those properties that are defined in the schema (validator). It is a partial schema coverage.
Here is the counter example: the value of the property “orderLineItems” is not in compliance, and so the insertion fails:
> db.orders.insert({ "orderId": NumberInt(4), "orderDate": new Date("2017-09-30"), "orderLineItems": ["b", "g"], "preferredColor": "red" })
WriteResult({ "nInserted": 0, "writeError": { "code": 121, "errmsg": "Document failed validation" } })
Update Strictness and Partial Schema Coverage
The following updates an existing document:
> db.orders.update({ "orderId": NumberInt(2) }, { "$set": { "orderDate": new Date("2017-10-01") } })
WriteResult({ "nMatched": 1, "nUpserted": 0, "nModified": 1 })
In part 1 of this blog series the order with identifier 1 was updated to add a property “specialInstructions”. This is not schema compliant, however, the update is possible as it does not violate that part of the document that is covered by the schema.
> db.orders.update({ "orderId": NumberInt(1) }, { "$set": { "specialInstructions": "Drop of in front, not back of location" } })
WriteResult({ "nMatched": 1, "nUpserted": 0, "nModified": 1 })
Partial schema coverage applies to update as well, not just to inserts.
An example of a non-compliant update is the following:
> db.orders.update({ "orderId": NumberInt(2) }, { "$set": { "orderDate": "2017-09-30" } })
WriteResult({ "nMatched": 0, "nUpserted": 0, "nModified": 0, "writeError": { "code": 121, "errmsg": "Document failed validation" } })
Summary
MongoDB supports partial schema coverage in strict mode, meaning, properties defined in the schema must match the schema, however, properties not specified in the schema can be added or modified without rejection.
This means (again) that examining the JSON schema validator of a MongoDB collection only indicates properties common to all documents, but not the complete set of properties of all documents.
The next blog examines the non-strict validation setting of a JSON schema validator in MongoDB.
Go [ JSON | Relational ] SQL!
Disclaimer
The views expressed on this blog are my own and do not necessarily reflect the views of Oracle.