The Basics
In the last discussion we got mongoose installed and up and running. Remember that mongoose is going to connect us to our Mongo DataBase and allow us to manipulate our data through JavaScript.
The first thing to understand in working with mongoose is the models. Mongoose works off of models, which are JavaScript classes, that we create, with the assistance of mongoose, that represent the information within a Mongo DataBase. More specifically, a model will represent data in one Collection. This is important because we have to create a model, for every Collection in the DataBase we are using.
Server Code
In our last discussion we set up our working environment, installed express, nodemon, and mongoose. We then started our server file (index.js) with the code that connects mongoose to our Mongo dataBase port (27017). Here's the server code we have so far:
- JavaScript
- const mongoose = require('mongoose');
- mongoose.connect( 'mongodb://127.0.0.1:27017/movieApp' )
-
- .then( () => {
- console.log('Mongoose connected on port mongodb://127.0.0.1:27017/');
- console.log('Connected to movieApp DB');
- })
- .catch(err => {
- console.log('Connection Error!');
- console.log(err);
- })
So we've imported mongoose and told it to connect to our movieApp Mongo dataBase on port 27017. We then set up the error trap to display a message upon successful connection to the dataBase, or to display the error, if there is one.
Now we can start building our models and more information on these, can be found here. There is a whole list of methods here, that every model we make will have access to. Remember, a model is a JavaScript class, that is your primary tool, for interacting with MongoDB.
Defining a Schema
So, as stated above, a model is a JavaScript class, that is your primary tool, for interacting with MongoDB. This model represents the data in a Mongoose dataBase, or more specifically, a dataBase Collection. Let's take a deeper dive into models.
In order to utilize a model, the first thing we need to do is to define a Schema. Ok, so what is a Schema?
- A mongoose Schema, defines the structure and properties of a Document in a MongoDB Collection. This Schema is a way to define expected properties and values along with the constraints and indexes. A Compiled version of the Schema is known as a Model. More info in schemas can be found here, and also here.
So we're going to need to define a schema, and we said previously that we wanted create a "Movie App" dataBase. So our schema will need to define the properties of a movie, in this example. Properties such as:
- Movie Name
- Year Released
- User Score
- MPAA Rating
So define the schema, we need to think about what types of data theses properties are.
- Movie Name : string data
- Year Released : numeric data
- User Score : numeric data
- MPAA Rating : string data
and now we are ready to actually define our schema, like so:
- const movieSchema = new mongoose.Schema({
- title: string,
- year: number,
- score: number,
- rating: string
- });
As you can see, the schema is defining what kind of data, each property of a movie, will contain. *note: that there are several different data types that can be used, and a list of these can be found here.
Also, the defining names we've used here (title, year, score, and rating) are important in that they must match what is in the actual collection. In the collection itself, the names must also be (title, year, score, and rating).
Defining a Model
Ok, we now have our schema created, so next we can create our model, which we will define to use our schema. The basic syntax for a model is:
- mongoose.model('modelName', schemaName);
Now it's important to note that the modelName is "singular" and that the first letter is Capitol, and that the schemaName must match our pre-defined schema name. So the specific model for our movieApp would look like this:
- mongoose.model('Movie', movieSchema);
So Movie is the name of this specific model, and movieSchema is the name of this specific schema.
Mongoose will now take this model (Movie), and create a Collection in our dataBase called movies. What? It did what here? It took our "modelName" from our model (Movie), lowerCased it, & pluralized it, then created a new Collection with the modified name (movies).
So our model name is "Movie", and our new Collection name that the model created. becomes "movies".
Next we assign our model to a variable:
- const Movie = mongoose.model('Movie', movieSchema);
This creates a "Movie" class. Notice that we normally use the same variable name as we used for the model name.
And now that we have a "Movie Class", we can create "new instances" of our class, like so:
- const badSanta = new Movie({
- title: 'Bad Santa',
- year: 2003
- score: 7.0
- rating: 'R'
- })
So our dataBase name is movieApp, and our Model should have created a Collection called movies. We've created a new instance of our "Movie" class for "Bad Santa", but so far we haven't actually uploaded anything to the dataBase.
Uploading the Data
So now we're finally ready to add our "Bad Santa" movie to our dataBase. We've created our schema, (movieSchema). We've created our Movie model, (Movie). We've created our Movie class, (Movie) and finally, we've created a new instance of our Movie Class, (badSanta) for the movie "Bad Santa".
To upload the new data, we're going to start up our Terminal, navigate to our project directory, and run [node].
Once node is running, we enter:
This should "load" our index.js file into our node environment. And if we enter [ badSanta ], we should get the data for badSanta:
- {
- title: 'Bad Santa',
- year: 2003,
- score: 7,
- rating: 'R',
- _id: new ObjectId('67ffdf88bf46707dab2fcd96')
- }
Notice that it has automatically assigned a "unique" ID to our Document.
And now we are ready to actually "write" our data to the dataBase by using the command:
This should now insert the data for our badSanta movie, into our movieApp dataBase, under the movies Collection.
Also, notice that this returns a promise, so we could create a "try/catch" error routing to ensure the data was uploaded, or return an error, if it was not uploaded.
We can verify this did actually upload to our dataBase by exiting out of node [exit], and loading MongoDB [mongosh]. Once in the Mongo Shell, enter [use movieApp] to make our movieApp the "active" dataBase. And finally do a find(), [db.movies.find()] to list all of the Documents in the movies Collection, and we should see:
- {
- _id: new ObjectId('67ffdf88bf46707dab2fcd96'),
- title: 'Bad Santa',
- year: 2003,
- score: 7,
- rating: 'R',
- __v: 0
- }
I'm not sure what the __v: 0 represents, but the rest of the output shows us that the Bad Santa data was indeed "uploaded" into our movies Collection of our movieApp dataBase.
On last point of discussion here. We can also use this procedure to change or edit an existing Document. Let's say we change the user score from 7 to 8.5:
and re-upload the file (run node - .load index.js - badSanta.save()), we can look at out Document in Mongoose and see that the "score" data has actually changed to 8.5.
Inserting Many
So we saw how to create a new instance of our Movie class, and then use movieClassName.save() it to upload it into the dataBase. But what if we wanted to upload many items into the dataBase at one time.
Well, in MongoDB, we could use db.collection.insertMany(). But remember, we're trying to write mongoose code so we can perform the uploading through a JavaScript interface. And fortunately, mongoose includes a similar method called insertMany().
To use this method, we still need to create our schema, and model. All we have to do in JavaScript is to create an array, in our index.js file, that will contain all of the new data for the new movies, like so:
- Movie.insertMany([
- { title: 'Amelie', year: 2001, score: 8.3, rating: 'R' },
- { title: 'Alien', year: 1979, score: 8.1, rating: 'R' },
- { title: 'The Iron Giant', year: 1999, score: 7.5, rating: 'PG' },
- { title: 'Stand By Me', year: 1986, score: 8.6, rating: 'R' },
- { title: 'Moonrise Kingdom', year: 2012, score: 7.3, rating: 'PG-13' }
- ])
First, notice that each set of movie data is it's own object. Also notice that all of these objects are combined within an array.
Now this is a entirely different process than the .save() method we used previously. If we are only uploading ONE single new class instance of the Movie class, then we need to use the .save() method, like so: badSanta.save()
But if we are trying to upload data for many movies, we need to use the insertMany() method as shown here. This process is basically creating a direct line in to MongoDB and insert all of the movies at once.
And lastly, because insertMany() returns a promise, we can use .then/.catch to process the result.
-
- .then(data => {
- console.log("Movie Data Uploaded:");
- console.log(data);
- })
All that's left to do now is to fire up out Terminal application and run node index.js. And here is the resulting output from the Terminal:
- Movie Data Uploaded:
- [
- {
- title: 'Amelie',
- year: 2001,
- score: 8.3,
- rating: 'R',
- _id: new ObjectId('680016b78718461efab2c30d'),
- __v: 0
- },
- {
- title: 'Alien',
- year: 1979,
- score: 8.1,
- rating: 'R',
- _id: new ObjectId('680016b78718461efab2c30e'),
- __v: 0
- },
- {
- title: 'The Iron Giant',
- year: 1999,
- score: 7.5,
- rating: 'PG',
- _id: new ObjectId('680016b78718461efab2c30f'),
- __v: 0
- },
- {
- title: 'Stand By Me',
- year: 1986,
- score: 8.6,
- rating: 'R',
- _id: new ObjectId('680016b78718461efab2c310'),
- __v: 0
- },
- {
- title: 'Moonrise Kingdom',
- year: 2012,
- score: 7.3,
- rating: 'PG-13',
- _id: new ObjectId('680016b78718461efab2c311'),
- __v: 0
- }
- ]