Skip to content

Instantly share code, notes, and snippets.

@cklanac
Last active November 3, 2018 08:50
Show Gist options
  • Save cklanac/2bfc80388ea4c5b938fff950717e8557 to your computer and use it in GitHub Desktop.
Save cklanac/2bfc80388ea4c5b938fff950717e8557 to your computer and use it in GitHub Desktop.
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.

Requirements

  • Install Mongoose
  • Update the config.js file with database connection information
  • Create a notesSchema and Note model
  • Seed the database
  • Create initial queries in scratch file
    • Convert _id to id and remove __v using toObject
  • Update server.js file to connect to the database
  • Create Notes endpoint

Set up your Project repo

  • Find 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.

    • Name the new repo "[YOUR-NAME]-noteful-v3".
    • Do not initialize the repository with a README.
  • 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.

Install Mongoose

To get started, npm install mongoose and then confirm mongoose has been saved to the dependencies property of your package.json file.

Update 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 of DATABASE_URL mentioned in the curriculum. MONGODB_URI is used by Heroku's mLab Add-On which minimizes the number of changes when deploying.

Create a notesSchema and a Note Model

Create /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 String

Plus additional date fields to track create and update timestamps

  • createdAt Defaults to now when creating a new document
  • updatedAt Saves the current date when updating a field

Add 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!

Seed the database

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!

Create queries in a scratch file

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:

  • (done) Find/Search for notes using Note.find
  • Find note by id using Note.findById
  • Create a new note using Note.create
  • Update a note by id using Note.findByIdAndUpdate
  • Delete a note by id using Note.findByIdAndRemove

Commit your changes!

MINI CHALLENGE: add reg exp search to content field

In 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.

PRO TIP - toObject transform

Notice 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!

Update 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!

Update /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.

  • Find All notes (search by title) using Note.find
  • Find Note by id using Note.findById
  • Create a new note using Note.create
  • Update a note by id using Note.findByIdAndUpdate
  • Delete a note by id using Note.findByIdAndRemove

Merge and Push

Once you are happy with your solution. Checkout master and merge your feature branch and push your changes to Github.

Solutions

You can view an example solution and compare the differences between branches

  • Solution: You can find the example solution in the solution/01-notes branch in the upstream repo.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment