Mongo & Mongoose Continued
Objectives |
---|
Review Mongoose setup in a Node/Express app |
Find documents with Mongoose |
Update and delete documents with Mongoose |
Review: What is Mongoose?
Mongoose</a> is an ORM (Object-Relational Mapping) for the non-relational, document-based database MongoDB.
An ORM is a layer between our application and our database, which allows us to query and manipulate data in the language and structure of our application.
Mongoose allows us to use JavaScript and Object-Oriented Programming to talk to our database, making our code DRY-er and eliminating the need to manually query our Mongo database.
Review: Mongoose Setup
In the terminal, add Mongoose to your application's node modules.
$ npm install --save mongoose
In
server.js
, require Mongoose and connect to the database you're using for your application.// server.js var mongoose = require('mongoose'); mongoose.connect('mongodb://localhost/catchphrasely');
At this point, if you haven't already created the database you're using, do so in the terminal. You'll need to start up MongoDB by running:
$ mongod
Note: If you already have an instance of MongoDB running, you'll get an error at this step. If that's the case, you can move on to the next step, since MongoDB is already running!
In a separate terminal tab, create and connect to your database. In the example, our new database is called
catchphrasely
.$ mongo $ use catchphrasely
In your application, create a folder called
models
with a file for your first model. In the example, we have aPhrase
model, so our model's filename isphrase.js
. Your folder structure should look similar to this:| catchphrasely | models - phrase.js | public | scripts - phrases.js | styles - phrases.css | views - index.html - .gitignore - package.json - server.js
In your model file (e.g.
phrase.js
), create the model schema, and export it so that you can require it in other parts of your app.// phrase.js var mongoose = require('mongoose'), Schema = mongoose.Schema; var PhraseSchema = new Schema({ word: String, definition: String }); var Phrase = mongoose.model('Phrase', PhraseSchema); module.exports = Phrase;
In
server.js
, require your model.// server.js var Phrase = require('./models/phrase');
Review: RESTful Routing
HTTP Verb | Path | Description |
---|---|---|
GET | /api/phrases | Get all phrases |
POST | /api/phrases | Create new phrase |
GET | /api/phrases/:id | Get one phrase |
PUT | /api/phrases/:id | Update a phrase |
DELETE | /api/phrases/:id | Delete a phrase |
Note: We can use /api
to differentiate our API routes from any static routes in our application (like our root route /
, which renders our index.html
). The /api
part of the routes is not required and is not a part of RESTful routing.
CRUD Operations with Mongoose
Get all: .find()
We can use .find()
to get all documents in the collection.
// get all phrases
app.get('/api/phrases', function (req, res) {
// find all phrases in db
Phrase.find(function (err, phrases) {
res.json(phrases);
});
});
Note: We can also use .find()
to get a specific set of documents in the collection (rather than ALL documents) by setting conditions. Read more in the docs.
Create: new
and .save()
We've seen the new
keyword before! It creates new instances of an object. We use it here to create new instances of our Phrase
model. We then call .save()
to store the new phrase in our database.
// create new phrase
app.post('/api/phrases', function (req, res) {
// create new phrase with form data (`req.body`)
var newPhrase = new Phrase({
word: req.body.word,
definition: req.body.definition
});
// save new phrase in db
newPhrase.save(function (err, savedPhrase) {
res.json(savedPhrase);
});
});
Get one: .findOne()
We can use .findOne()
to return the first document in the collection that matches certain criteria. In this case, we're looking for a phrase with our target id.
// get one phrase
app.get('/api/phrases/:id', function (req, res) {
// set the value of the id
var targetId = req.params.id;
// find phrase in db by id
Phrase.findOne({_id: targetId}, function (err, foundPhrase) {
res.json(foundPhrase);
});
});
Note: The .findById()
method will also return a single document matching a specified id field.
Update: .findOne()
and .save()
Similar to the last example, we can use .findOne()
to find the document with our target id. After updating the document, we use .save()
to persist our changes to the database.
// update phrase
app.put('/api/phrases/:id', function (req, res) {
// set the value of the id
var targetId = req.params.id;
// find phrase in db by id
Phrase.findOne({_id: targetId}, function (err, foundPhrase) {
// update the phrase's word and definition
foundPhrase.word = req.body.word;
foundPhrase.definition = req.body.definition;
// save updated phrase in db
foundPhrase.save(function (err, savedPhrase) {
res.json(savedPhrase);
});
});
});
Delete: .findOneAndRemove()
The .findOneAndRemove()
method takes care of finding the document with our target id and removing it from the database.
// delete phrase
app.delete('/api/phrases/:id', function (req, res) {
// set the value of the id
var targetId = req.params.id;
// find phrase in db by id and remove
Phrase.findOneAndRemove({_id: targetId}, function (err, deletedPhrase) {
res.json(deletedPhrase);
});
});
Note: Another way to achieve the same functionality is by finding the document first (using .findOne()
or .findById()
) and calling .remove()
on the found document.
Challenges (& Tonight's Homework)
Add Mongo/Mongoose to your Project 0 Microblog. If you would like to start with fresh code, you can clone this Microblog starter code.
Base Challenges
- Set up Mongoose in your Microblog app. This includes installing the Mongoose module, creating a schema for your blog posts, and requiring the schema in your
server.js
. - Use Mongoose methods to perform all of your API's CRUD operations. Your app should have five API routes:
- GET
/posts
should get all the posts from the database collection. - POST
/posts
should create a new post in the database collection. - GET
/posts/:id
should get one post document. - PUT
/posts/:id
should update a post document. - DELETE
/posts/:id
should delete a post document.
- GET
- Test all your API routes with Postman before testing if the addition of Mongoose affected anything on your client-side. Note: Your Mongo documents have an
_id
attribute, rather thanid
, so you'll need to update any instances ofid
on the client-side. - Submit the link to your project on GitHub in the homework submission form.
Stretch Challenges / Bonus
- Read about validations</a> and the built-in required validator in Mongoose.
- Add the required validator to all fields in your blog post schema.
- Super Bonus: In your API routes to create and update blog posts, respond with the error if the required validation is not met.
Evening Reading
For tomorrow morning, read "Model One-to-One Relationships with Embedded Documents", "Model One-to-Many Relationships with Embedded Documents", and "Model One-to-Many Relationships with Document References" from the Mongo docs.