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 toObjectserver.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 installto 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.jsIn 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_URIhere, instead ofDATABASE_URLmentioned in the curriculum.MONGODB_URIis 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.findNote.findByIdNote.createNote.findByIdAndUpdateNote.findByIdAndRemoveCommit 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.jsUpdate 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.jsThis 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.findNote.findByIdNote.createNote.findByIdAndUpdateNote.findByIdAndRemoveOnce 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.