Creating a Schema
In the REST API, data is represented through resources, which correspond to users and cards in the "Around the U.S." project. Each of these resources must correlate with a predetermined structure. For example, every user has a name along with other information about themselves. Let's have a go at setting up a schema for a user via Mongoose. We do this using the mongoose.Schema() constructor to create a new instance of the schema:
// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { // every user has a name field, the requirements for which are described below:
type: String, // the name is a string
required: true, // every user has a name, so it's a required field
minlength: 2, // the minimum length of the name is 2 characters
maxlength: 30, // the maximum length is 30 characters
},
pronouns: {
type: String, // the pronouns are a string
enum: ['they/them', 'she/her', 'he/him', 'other pronouns'] // every user can choose their pronouns
},
about: String, // type: String
});
Save
This schema ensures that every user in the system has:
a name between 2 and 30 characters long
pronouns that can take one of the four assigned values
an about property, which is a string
You probably noticed the enum option that Mongoose uses. Enumerations are special data types that restrict a variable to take only one value from a predefined set. In Mongoose schemas, enum type adds a validator to the field which checks whether it's strictly equal to one of the unique values of a specific array.
Sometimes, the standard features of a schema are insufficient for ensuring that data is entered correctly, but Mongoose provides more precise ways of validating information. For example, we can make use of the validation property. This property is an object, which in turn includes the following properties:
validator — a validation function. It returns a boolean value.
message — an error message. It is rendered if the validator function returns false.
Here's an example. Let's add the age property to the userSchema and restrict its value from being anything less than 18:
// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { // every user has a name field, the requirements for which are described below:
type: String, // the name type is a string
required: true, // every user has a name, so it's a required field
minlength: 2, // the minimum length of the name is 2 characters
maxlength: 30, // the maximum length is 30 characters
},
pronouns: {
type: String, // the pronouns are a string
enum: ['they/them', 'she/her', 'he/him', 'other pronouns'] // every user can choose their pronouns
},
age: { // every user has an age field
type: Number, // the age type is a number
required: true, // the user has to specify their age
validate: { // describe the validate feature
validator(v) { // validator is a data validation feature. v is the age value
return v >= 18; // if the age is less than 18, it will return false
},
message: 'Sorry. You have to be at least 18 years old', // when the validator returns false, this message will be displayed
}
},
about: String, // type: String
});
Save
This is a very basic form of validation. We can do much more complex validation using regular expressions, which we'll learn about in the next chapter.
Anyway, let's go back to data types. When creating schemas, we will be using 5 basic data types:
String
Number
Date
Boolean // logic: true or false
Array
Save
Subdocuments
If you use another schema as a property of your schema, you'll have to use the Schema method twice:
the first call is needed to create a schema that will describe the property's structure
the second call will pass the schema to the property. It should have the following structure:
// models/user.js
const mongoose = require('mongoose');
// create a schema for the "Pet" document
const petSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 30,
},
age: Number
});
// once the schema is ready, pass it to the property which should correspond to this template:
const userSchema = new mongoose.Schema({
...
pet: petSchema // describe the pet property with this schema
});
Save
Array Properties
Arrays are used to store multiple data items of the same type. This is why the schema of an array is a schema for a single array element inside square brackets:
// models/user.js
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
...
hobbies: [{ // describe the schema for a single element and put it in square brackets
type: String,
minlength: 2,
maxlength: 30,
}]
});
Save
This schema defines the hobbies property. It must contain an array of strings, each one from 2 to 30 characters in length.
Creating a Model Based on a Schema
Our schema now describes what a database document should look like. Let's proceed to the next stage, which is creating the documents themselves. To do this, we will build a model based on the schema.
A model is basically a wrapper around the schema. It enables us to read, add, delete, and update documents. The mongoose.model() method is used to create models in Mongoose:
// models/user.js
const mongoose = require('mongoose');
// Describe the schema:
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
minlength: 2,
maxlength: 30,
},
about: String,
});
// create the model and export it
module.exports = mongoose.model('user', userSchema);
Save
We passed two arguments to the mongoose.model method: the name of the model and the schema which will describe future documents.
It can get a little confusing at this point, so let's go over this again. The first argument (the name of the model) must be a singular noun. However, Compass displays it as a plural. This is because Mongoose automatically adds an 's' at the end of the collection name:
'user' has become 'users'
Recap: Model Creation
Set the API resources
Describe the resource schemas
Create models based on the schemas
Once the models are ready, you can use them to interact with the database i.e., to create, edit, and delete documents. We'll get to this in the next lesson.
Additional links
Schema types in Mongoose: https://mongoosejs.com/docs/schematypes.html
More information about schemas: https://mongoosejs.com/docs/guide.html