Challenge 12: Mongoose
For this challenge you will clone the Noteful V3 starter and add mongoose
to your Noteful app, create the endpoints for Notes.
config.js
file with database connection informationnotesSchema
and Note
model_id
to id
and remove __v
using toObject
server.js
file to connect to the databaseFind the noteful-app-v3
pinned to your Cohort's GitHub Organziation
Clone the noteful-app-v3
repo to your local development environment
Rename the origin
to upsteam
using git remote rename origin upstream
On GitHub create a new repo in your Cohort org on Github.
On the next page find the section titled …or push an existing repository from the command line and run the two commands
Verify your remotes are configured correctly. Enter git remote -v
, you should see two remotes: one called origin
pointing to your repo on GitHub and one named upstream
pointing Thinkful's repo.
Remember to run
npm install
to install the project dependencies. And create a feature branch for your development work.
To get started, npm install mongoose
and then confirm mongoose
has been saved to the dependencies
property of your package.json
file.
config.js
In the config.js
file, add a MONGODB_URI
property like the following:
module.exports = {
PORT: process.env.PORT || 8080,
MONGODB_URI: process.env.MONGODB_URI || 'mongodb://localhost/noteful'
};
NOTE: we are using
MONGODB_URI
here, instead ofDATABASE_URL
mentioned in the curriculum.MONGODB_URI
is used by Heroku's mLab Add-On which minimizes the number of changes when deploying.
notesSchema
and a Note
ModelCreate /models/note.js
file. This is where you will define the Note Schema and create a Note Model. Since this is your first schema, we'll help you along.
You will need to create a schema with the following criteria:
title
a Required String.content
a StringPlus additional date fields to track create and update timestamps
createdAt
Defaults to now when creating a new documentupdatedAt
Saves the current date when updating a fieldAdd the following to the file:
const mongoose = require('mongoose');
const noteSchema = new mongoose.Schema({
title: { type: String, required: true },
content: String
});
// Add `createdAt` and `updatedAt` fields
noteSchema.set('timestamps', true);
Now, create a Note
model and export it. Remember, the name you pass to the mongoose.model()
method is used to create the lowercase and pluralized collection in Mongo.
module.exports = mongoose.model('Note', noteSchema);
Commit your changes!
Next you need to seed the database with sample data to make development easier. We will not use mongoimport
to seed the database, instead you should create a seed-database utility which uses the Model and Schema you created above. The script connects to the server, drops the database and populates it with your data.
Create a /utils/seed-database.js
file and add the script below. Explore it by adding your own console.log()
.
const mongoose = require('mongoose');
const { MONGODB_URI } = require('../config');
const Note = require('../models/note');
const seedNotes = require('../db/seed/notes');
mongoose.connect(MONGODB_URI)
.then(() => mongoose.connection.db.dropDatabase())
.then(() => Note.insertMany(seedNotes))
.then(results => {
console.info(`Inserted ${results.length} Notes`);
})
.then(() => mongoose.disconnect())
.catch(err => {
console.error(err);
});
Next, run the execute the process by running node ./utils/seed-database.js
and check your database collection to verify the documents were inserted properly.
Commit your changes!
Next, you need to create the CRUD operations in a clean isolated environment. So create a scratch/queries.js
file. To help get started here is a sample .find()
.
const mongoose = require('mongoose');
const { MONGODB_URI } = require('../config');
const Note = require('../models/note');
mongoose.connect(MONGODB_URI)
.then(() => {
const searchTerm = 'lady gaga';
let filter = {};
if (searchTerm) {
filter.title = { $regex: searchTerm };
}
return Note.find(filter).sort({ updatedAt: 'desc' });
})
.then(results => {
console.log(results);
})
.then(() => {
return mongoose.disconnect()
})
.catch(err => {
console.error(`ERROR: ${err.message}`);
console.error(err);
});
Run the scratch file using node ./utils/queries.js
or nodemon ./utils/queries.js
to see the results.
Your Turn!
We've provided the first solution, your challenge is to create the other queries:
Note.find
Note.findById
Note.create
Note.findByIdAndUpdate
Note.findByIdAndRemove
Commit your changes!
content
fieldIn this mini challenge you'll go back and improve the Note.find()
query.
Using the $or
Operator, update the query to search both the title
and the content
fields.
toObject
transformNotice the output contains an _id
and __v
. Whenever you return a mongoose document instance using console.log(document)
or res.json(document)
, it is converted from a mongoose document object to a standard JSON object. We can use this transformation process convert _id
to id
and remove the superfluous __v
property. Add this statement to your /models/note.js
schema file.
noteSchema.set('toObject', {
virtuals: true, // include built-in virtual `id`
versionKey: false, // remove `__v` version key
transform: (doc, ret) => {
delete ret._id; // delete `_id`
}
});
Rerun queries.js
and you should see the updates.
For more information check out the documentation
Commit your changes!
server.js
Update the server.js
file to require mongoose and connect to the database.
Towards the top of the file, add require('mongoose')
.
Next, update the config statement to pull in MONGODB_URI
.
const { PORT, MONGODB_URI } = require('./config');
Lastly, add mongoose.connect(MONGODB_URI)
. You'll want to add it towards the bottom of the page, next to the app.listen
call. This will make it easier to fix when we add integration tests to the mix later.
// Connect to DB and Listen for incoming connections
mongoose.connect(MONGODB_URI)
.then(instance => {
const conn = instance.connections[0];
console.info(`Connected to: mongodb://${conn.host}:${conn.port}/${conn.name}`);
})
.catch(err => {
console.error(`ERROR: ${err.message}`);
console.error('\n === Did you remember to start `mongod`? === \n');
console.error(err);
});
app.listen(PORT, function () {
console.info(`Server listening on ${this.address().port}`);
}).on('error', err => {
console.error(err);
});
Commit your changes!
/routes/notes.js
This is the main hurdle for this challenge.
Update the /routes/notes.js
file with the queries above. The /routes/notes.js
file contains skeleton endpoints which you need to fill in using the queries you created above.
Note.find
Note.findById
Note.create
Note.findByIdAndUpdate
Note.findByIdAndRemove
Once you are happy with your solution. Checkout master
and merge your feature branch and push your changes to Github.
You can view an example solution and compare the differences between branches
solution/01-notes
branch in the upstream repo.