Lesson 14. Building models with Mongoose

In lesson 13, you got up and running with MongoDB. With a database connected to your Node.js application, you’re ready to save and load data. In this lesson, you apply a more object-oriented approach to your data. First, you install the Mongoose package, a tool that provides a syntactic layer between your application logic and your database. Mongoose allows you to convert your application data to fit a model structure. Later in the lesson, you build your first model and schema to represent newsletter subscribers to your recipe application.

This lesson covers

  • Installing and connecting Mongoose to your Node.js application
  • Creating a schema
  • Building and instantiating Mongoose data models
  • Loading and saving data with custom methods
Consider this

You finally have a database connected to your application, but data can change over time. One day, you may want to require all recipes to follow the same format. How can you determine such a structure and make sure that all saved data follows that structure’s rules?

In this lesson, you explore Mongoose, a library used to create model schema. When you use these schemas, your data begins to follow strict rules that only you can customize.

14.1. Setting up Mongoose with your Node.js application

You’ve already experienced Express.js and seen how it helps you handle HTTP requests and responses. Similarly, other packages are available to assist with the communication between your Node.js application and its database. The tool you’re going to use is called Mongoose. Mongoose is an object-document mapper (ODM) that allows you to run Mongo-DB commands in a way that preserves the object-oriented structure of your application. With MongoDB alone, for example, it’s difficult to keep one saved document consistent with the next. Mongoose changes that situation by offering tools to build models with schemas defining what type of data can be saved.

I discussed model-view-controller (MVC) architecture in unit 2 and described how controllers communicate with both views and models to ensure that the correct data flows through the application. A model is like a class for a JavaScript object that Mongoose uses to organize your database queries. In this section, you install Mongoose and see what a model looks like in your application (figure 14.1).

Figure 14.1. Models created with Mongoose map to documents in MongoDB.

To install Mongoose, run npm i mongoose -S within your project folder in terminal. With Mongoose, you no longer need to require mongodb at the top of main.js or use any of the MongoDB code from lesson 13. Add the code in listing 14.1 to main.js. Require mongoose into the application file. Set up the application’s connection to your MongoDB database. (The same rules apply here as in a normal MongoDB connection.) Then assign the database connection to the db variable, which you can use later in the file for data changes or database state changes.

Listing 14.1. Configuring Mongoose with your Node.js application in main.js
const mongoose = require("mongoose");         1
mongoose.connect(
  "mongodb://localhost:27017/recipe_db",      2
  {useNewUrlParser: true}
);
const db = mongoose.connection;               3

  • 1 Require mongoose.
  • 2 Set up the connection to your database.
  • 3 Assign the database to the db variable.
Note

Remember to have the MongoDB server running in the background. To run Mongo-DB, enter mongod in a terminal window.

That’s all you need to do to set up Mongoose. You can log a message as soon as the database is connected by adding the code in the next listing to main.js. The database connection runs the code in the callback function (the log message) only once upon receiving an “open” event from the database.

Listing 14.2. Log a message when the database is connected in main.js
db.once("open", () => {                                             1
  console.log("Successfully connected to MongoDB using Mongoose!");
});

  • 1 Log a message when the application connects to the database.

In the next section, you explore how to model your data to make best use of Mongoose.

Quick check 14.1

Q1:

What is an ODM?

QC 14.1 answer

1:

ODM is an object-document mapper, which is the role of Mongoose in your application development. ODM (like an object-relational mapper) makes it easier to think purely in terms of objects in your application and not worry about how your data is structured in the database.

 

14.2. Creating a schema

A schema is like a class definition in some languages or, more broadly, a blueprint for how you want data to be organized for specific objects in your application. To avoid inconsistent data, where some documents have an email field and others don’t, for example, you can create a schema stating that all contact objects need to have an email field to get saved to the database.

Because you want to add a newsletter subscription form to the recipe application, create a schema for the subscriber. Add the code from listing 14.3 to main.js. mongoose.Schema offers a constructor that allows you to build a schema object with the given parameters. Then add object properties to state the name of the object’s field and its data type. Someone’s name can’t be a number, for example.

Listing 14.3. Subscriber schema in main.js
const subscriberSchema = mongoose.Schema({     1
  name: String,                                2
  email: String,
  zipCode: Number
});

  • 1 Create a new schema with mongoose.Schema.
  • 2 Add schema properties.
Note

MongoDB isn’t enforcing your schema; Mongoose is. For more information about Mongoose schema data types, visit http://mongoosejs.com/docs/schematypes.html.

Now that the schema is defined, you need to apply it to a model by using const Subscriber = mongoose.model(Subscriber, subscriberSchema). The model is what you’ll use to instantiate new Subscriber objects, and the schema you created can be used for that model. The model method takes a model name of your choosing and a previously defined schema (in this case, the subscriberSchema).

You can instantiate new objects from this model by referring to Subscriber. You have two ways to generate new objects, as shown in listing 14.4. You can construct a new instance of the Subscriber model by using the new keyword and by passing properties that abide by the subscriberSchema earlier in the section. To get this newly created Subscriber object into the database, you can call save on it and handle any errors or returned data through a callback function.

An error may have to do with data that doesn’t match the schema types you defined earlier. The saved item returns data that you can use elsewhere in the application. You may want to thank the subscriber by name for signing up, for example. create does what new and save do in one step. If you know that you want to create and save the object right away, use this Mongoose method.

Note

Instantiating objects from your Mongoose models is similar to instantiating Java-Script objects. The new keyword can be used with JavaScript Array and other data types.

Listing 14.4. Statements to create and save models in main.js
var subscriber1 = new Subscriber({
  name: "Jon Wexler",
  email: "[email protected]"
});                                              1

subscriber1.save((error, savedDocument) => {     2
  if (error) console.log(error);                 3
  console.log(savedDocument);                    4
});

Subscriber.create(
  {
    name: "Jon Wexler",
    email: "[email protected]"
  },
  function (error, savedDocument) {              5
    if (error) console.log(error);
    console.log(savedDocument);
  }
);

  • 1 Instantiate a new subscriber.
  • 2 Save a subscriber to the database.
  • 3 Pass potential errors to the next middleware function.
  • 4 Log saved data document.
  • 5 Create and save a subscriber in a single step.

Add the code from the listings in this section to your main.js file. As soon as you start the application with node main.js, you should see your MongoDB recipe_db database populate with a new subscriber.

Quick check 14.2

Q1:

True or false: Using new Subscriber({ name:Jon, email:[email protected]}) saves a new record to your database.

QC 14.2 answer

1:

False. This code only creates a new virtual object. If you store the value of this line to a variable and call save on that variable, the new subscriber is stored in the database.

 

14.3. Organizing your models

Now that you have a way of saving data in the form of Mongoose models, you’ll want to organize your models so that they don’t clutter your main.js file. As you do for your views and controllers, create a models folder at the root level of your application. Within that folder, create a new file called subscriber.js.

This file is where you’ll move your model’s code. Move all the schema and model definition code to this file and the model to the file’s exports object. (See the following listing.) Any module that requires subscriber.js will have access to the Subscriber model. The schema doesn’t need to be made accessible outside the file.

Listing 14.5. Moving the schema and model to a separate module
const mongoose = require("mongoose"),
  subscriberSchema = mongoose.Schema({
    name: String,
    email: String,
    zipCode: Number
  });

module.exports = mongoose.model("Subscriber", subscriberSchema);    1

  • 1 Export the Subscriber model as the only module export.
Note

You need to require mongoose in this module because both the schema and model use Mongoose methods to work. Node.js loads a module into the project only once, so requiring it here shouldn’t slow your application; you’re telling Node.js that you want to use an already-loaded module.

Next, require this model in your main.js by adding const Subscriber = require(./models/subscriber) below your other required modules. Now you should be able to use the model the same way as before.

In main.js, find documents in your database by using Mongoose’s findOne and where query methods. As an example, you can use Subscriber.findOne({ name:Jon Wexler}) .where(email, /wexler/) to find and return one document that matches the criteria name where the email contains the string “wexler”.

This example custom query shows how flexible your queries can be to get the data you need. Mongoose lets you chain parts of a query and even store queries in a variable. You could create a variable var findWexlers and assign it to the code querying for emails with the word wexler. Then you could run the query later by using findWexlers.exec(). (For more on exec, see lesson 15.)

If you plan to run a query immediately without the exec method, you need a callback function with two arguments. The first argument represents any errors that occur, and the second argument represents any data returned by the database, as shown in the following listing. Try creating your own queries by following some of the example queries at http://mongoosejs.com/docs/queries.html.

Listing 14.6. Example query to run in main.js
var myQuery = Subscriber.findOne({
    name: "Jon Wexler"
  })
  .where("email", /wexler/);
myQuery.exec((error, data) => {
  if (data) console.log(data.name);
});                                     1

  • 1 Run a query with a callback function to handle errors and data.
Note

For queries indicating that multiple items will be returned from the database, you should expect an array. If no documents are found, you get an empty array.

Now you have the freedom to create more modules and save them by using their names instead of the MongoDB collection names.

In unit 4, you learn how to make a more-robust model whose values can be created, read, updated, and deleted—the four core model functions in a CRUD application. I discuss this approach in detail in that unit.

Quick check 14.3

Q1:

What two components are required for each field specified in a Mongoose schema?

QC 14.3 answer

1:

The schema requires a property name and data type.

 

Summary

In this lesson, you learned how to set up Mongoose and use your MongoDB connection to map data to your database. You also learned about some Mongoose syntax and methods. Through the steps in this lesson, you learned how to create a schema and model for storing persistent data. Last, you organized your models, clearing your main.js for new tools to come. In lesson 15, you clean up some of the functionality that you built in this lesson by implementing JavaScript promises in your database queries.

Try this

Eventually, you’ll create more models for your recipe application. Start to think about what those models will look like. You may need a model to represent the different types of courses offered through the program, for example. Try creating a schema and model for a recipe item.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.218.127.141