$jsonSchema operator in mongodb

Victory Osikwemhe - Sep 9 '20 - - Dev Community

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",
});

Enter fullscreen mode Exit fullscreen mode

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({})
Enter fullscreen mode Exit fullscreen mode

When you run the above, MongoDB will show you this beautiful error message

WriteResult({
    "nInserted" : 0,
    "writeError" : {
        "code" : 121,
        "errmsg" : "Document failed validation"
    }
})
Enter fullscreen mode Exit fullscreen mode

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"
  }
});
Enter fullscreen mode Exit fullscreen mode

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)
  }
});
Enter fullscreen mode Exit fullscreen mode

Everything is fine now.

They are two options above that controls the behaviour of the $jsonSchema validator

{
  validationLevel: "strict",
  validationAction: "error"
}
Enter fullscreen mode Exit fullscreen mode

$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

Security Guard

strict applies the validation rules on all insert and update operation, basically no invalid document will be allowed.

Hammer on the Head

db.student.updateOne({ email: "test@example.com"}, { $set: { dateOfBirth: "08/08/1997" } });
Enter fullscreen mode Exit fullscreen mode

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.

$jsonSchema Keywords

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 :)

. . .