Prior to MongoDB 3.6
, there was no way to define what value(s) a field in a MongoDB document will be (even if we love it's schema-less nature, we might still have that feeling to be able to do something like this), we resolved into using an ODM like mongoose to be able to define a schema for a collection.
From MongoDB 3.6 it became possible to define a schema for a collection, but it's not as concise and 100% intuitive with the Mongoose approach.
The $jsonSchema
is an evaluation operator in MongoDB, that does not only allow one define a schema for a collection, the $jsonSchema operator can also be used to match document(s) that meets a specific structure.
To be able to define a schema for a collection one has to use the db.createCollection
method
db.createCollection("student", {
validator: {
$jsonSchema: {
required: [
"email",
"phoneNumber",
"fullName",
"dateOfBirth",
"subjects",
"address",
],
bsonType: "object",
properties: {
email: {
bsonType: "string",
description: "Email Address of student",
},
phoneNumber: {
bsonType: "string",
description: "Phone Number of the student",
},
fullName: {
bsonType: "string",
description: "student full name",
},
dateOfBirth: {
bsonType: "date",
description: "Date of Birth of student",
},
subjects: {
enum: ["English", "Mathematics", "Biology", "Government"],
description: "Value specified does not match the required subject",
},
address: {
bsonType: "object",
required: ["city", "street"],
properties: {
city: {
bsonType: "string",
description: "City of the student",
},
street: {
bsonType: "string",
description: "Street of user",
},
houseNumber: {
bsonType: "int",
description: "House number of the student",
},
},
},
},
},
},
validationLevel: "strict",
validationAction: "error",
});
From the above code, you will see the use of bsonType
, bsonType
stands for binary json, it's like a superset of json, and it supports various data types such as 64bit integer and regular expression, more information about this here.
The use of bsonType
in the above code, is to specify what datatype a field accept, for the dateOfBirth
the accepted datatype is a date object.
Let's try to insert an empty document and see what happens.
db.student.insert({})
When you run the above, MongoDB will show you this beautiful error message
WriteResult({
"nInserted" : 0,
"writeError" : {
"code" : 121,
"errmsg" : "Document failed validation"
}
})
Now this brings us to the next point, the required
option, the required
option is an array of fields that must be exist in the document to be inserted. The validator requires the email
, phoneNumber
, fullName
, dateOfBirth
, subjects
and address
fields to be available when inserting a new document.
In our above example, we tried inserting an empty document, hence we got back that error. Let's correct this
db.student.insert({
email : "test@example.com",
phoneNumber : "+234111111",
fullName : "Victory Osikwemhe",
dateOfBirth : new Date("08/08/1996"),
subjects : "Physics",
address : {
city : "Abuja",
street : "Ademola Adetokunbo Crescent, Wuse 2"
}
});
Running the above operation in mongo cli, we will also be presented with the previous error, and it's as a result of the wrong value specified to the subjects
key. This brings us to what enum
does, enum
specifies the only values that a particular field is allowed to have, in our $jsonSchema validation object, we have something like this enum: [ "English", "Mathematics", "Biology", "Government" ]
for the subjects
field, and it's clear that "Physics" is not among the list, let's correct it by changing "Physics" to a valid value.
db.student.insert({
email : "test@example.com",
phoneNumber : "+234111111",
fullName : "Victory Osikwemhe",
dateOfBirth : new Date("08/08/1996"),
subjects : "Government",
address : {
city : "Abuja",
street : "Ademola Adetokunbo Crescent, Wuse 2",
houseNumber : NumberInt(22)
}
});
Everything is fine now.
They are two options above that controls the behaviour of the $jsonSchema validator
{
validationLevel: "strict",
validationAction: "error"
}
$jsonSchema
is also capable of validating update operations also.
The validationLevel
option specifies how well will MongoDB play with insert and update operation(s). This option only supports three values strict
, off
and moderate
.
off
does not perform any form of validation on the document that is been inserted or updated
strict
applies the validation rules on all insert and update operation, basically no invalid document will be allowed.
db.student.updateOne({ email: "test@example.com"}, { $set: { dateOfBirth: "08/08/1997" } });
Running the above code, the result will be a Document failed validation
error, because we are trying to update a field that only supports a date object.
moderate
applies the validation rules on all insert and existing valid document in the collection.
The validationAction
option controls how MongoDB reports the invalid document, it supports two values error
and warn
.
The error
value prevents the invalid document from been inserted in the collection, same applies to trying to update a document with an invalid field.
The warn
value logs out the error, but still allows the invalid document to be inserted/updated.
The $jsonSchema validator also have support for many keywords to further specify how a field should be validated.
The part 2 of this post will be on how to use $jsonSchema
in query conditions to match documents that meets the specified criteria.
Thanks for reading :)