Skip to content

Instantly share code, notes, and snippets.

@hillal20
Forked from luishrd/Character.js
Created May 10, 2018 18:22
Show Gist options
  • Save hillal20/90828d9fb66dc1a7af684ed006867acf to your computer and use it in GitHub Desktop.
Save hillal20/90828d9fb66dc1a7af684ed006867acf to your computer and use it in GitHub Desktop.
MongoDB Sprint
const router = require('express').Router();
const Bear = require('./bearModel');
router.post('/', function post(req, res) {
const bearData = req.body;
const bear = new Bear(bearData);
bear
.save()
.then(bear => {
res.status(201).json(bear);
})
.catch(err => {
res.status(500).json(err);
});
});
router.get('/', function get(req, res) {
Bear.find().then(bears => {
res.status(200).json(bears);
});
});
router.get('/:id', (req, res) => {
const { id } = req.params;
Bear.findById(id)
.then(bears => {
res.status(200).json(bears);
})
.catch(err => res.status(500).json(err));
});
// /api/bears/1234
router.delete('/:id', (req, res) => {
const { id } = req.params;
Bear.findByIdAndRemove(id)
.then(bear => {
if (bear) {
res.status(204).end();
} else {
res.status(404).json({ msg: 'Bear not found' });
}
})
.catch(err => res.status(500).json(err));
});
router.put('/:id', (req, res) => {
const { id } = req.params;
const update = req.body;
const options = {
new: true,
};
Bear.findByIdAndUpdate(id, update, options)
.then(bear => {
if (bear) {
res.status(200).json(bear);
} else {
res.status(404).json({ msg: 'Bear not found' });
}
})
.catch(err => res.status(500).json(err));
});
module.exports = router;
const mongoose = require('mongoose');
const definition = {
species: {
type: String,
required: true,
unique: true,
},
latinName: {
type: String,
required: true,
},
createdOn: {
type: Date,
default: Date.now,
},
};
const options = {
timestamps: true,
};
const bearSchema = new mongoose.Schema(definition, options);
const bearModel = mongoose.model('Bear', bearSchema, 'bears');
module.exports = bearModel;
const mongoose = require('mongoose');
const ObjectId = mongoose.Schema.Types.ObjectId;
const Character = mongoose.Schema({
name: { type: String, required: true },
edited: Date,
created: Date,
gender: String,
height: String,
hair_color: String,
skin_color: String,
eye_color: String,
birth_year: String,
key: { type: Number, unique: true },
homeworld_key: Number,
// add homeworld field that links the character to it's planet
homeworld: {
type: ObjectId,
ref: 'Planet',
},
});
module.exports = mongoose.model('Character', Character);
const express = require('express');
const Character = require('./Character.js');
const Film = require('../films/Film');
const router = express.Router();
// add endpoints here
router.get('/', function(req, res) {
Character.find()
.then(chars => res.status(200).json(chars))
.catch(err => {
res.status(500).json(err);
});
});
router.get('/:id', function(req, res) {
const { id } = req.params;
Character.findById(id)
.populate('homeworld', 'climate -_id')
.then(char => {
Film.find({ characters: id })
.select('title')
.then(films => {
const character = { ...char._doc, movies: films };
res.status(200).json(character);
});
})
.catch(err => {
res.status(500).json(err);
});
});
module.exports = router;
const mongoose = require('mongoose');
const ObjectId = mongoose.Schema.Types.ObjectId;
const Film = new mongoose.Schema({
created: { type: Date, default: Date.now },
episode: Number,
edited: { type: Date, default: Date.now },
planet_ids: [Number],
producer: String,
title: { type: String, required: true },
director: String,
release_date: String,
opening_crawl: String,
character_ids: [Number],
specie_ids: [Number],
key: { type: Number, unique: true },
starship_ids: [Number],
vehicle_ids: [Number],
// add fields for starships, vehicles, planets, characters and species
// to link them to the corresponding model
characters: [{ type: ObjectId, ref: 'Character' }],
planets: [{ type: ObjectId, ref: 'Planet' }],
});
module.exports = mongoose.model('Film', Film, 'films');
const express = require('express');
const Film = require('./Film.js');
const router = express.Router();
// add endpoints here /api/films?released=2005&producer=gary kurtz
router.get('/', function(req, res) {
let query = Film.find()
.select('episode producer title director release_date')
.populate('planets', 'name climate terrain gravity diameter')
.populate(
'characters',
'name gender height skin_color hair_color eye_color'
);
const { producer, released } = req.query;
if (producer) {
const filter = new RegExp(producer, 'i');
query.where({ producer: filter });
}
if (released) {
query.where({ release_date: { $regex: released, $options: 'i' } });
}
query.then(films => res.status(200).json(films));
});
module.exports = router;

Back End Journey

  • Build a RESTful API using Express and Node.js.
  • Persist API Data to a Database. (this week)
  • Secure an API.
  • Unit Testing.
  • Backend Project Week.

Day 1

  • verify mongo installation.
  • verify mongo is running (don't stop it until you're done working with it).
  • quick intro to databases.
  • what is NoSQL and what are document databases.
  • why MongoDB.
  • working with local instance of MongoDB. DBAAS options.
  • a BRIEF look at the mongo shell.
  • connecting to MongoDB from our API.
  • mongoose
    • what is it?
    • benefits and drawbacks.
  • mongoose Schemas ad Models.
  • define a basic document Schema and Model.
  • creating database documents.
  • querying all documents.
  • querying one document by id.

Database

Collection of data, organized, easy to get information out of it.

Query

Asking questions about our data or executing commands to operate on the stored data.

DBMS (DB Management System)

Software that provides a way to store/retrieve data.

Client <-> [ API <-> DB Server ]

NoSQL (Not Only SQL): a type of database

  • key-value pair
  • graph
  • document <- MongoDB
const user = {
  username: 'admin',
  password: 'secret',
};

MongoDB Server

  • databases (lambda)
    • collections (users, roles, products)
      • documents ({ _id: 'qeworjoasjf;lkjeorir0', username: 'admin' })
        • fields: _id, username

Why MongoDB

  • popular
  • mature
  • JS end to end
  • dynamic schemas (shape of the data [properties and data types])

cons

  • dynamic schemas
  • no joins

DBAAS (database as a service)

  • offer free 500mb tiers
  • MongoDB Atlas
  • mlab

Client < JSON > [ API (driver) ] < BSON > [ DB Server ]

Mongoose

  • wraps the native mongodb driver
  • schemas and models
  • middleware
  • validation
  • query builder
  • ...

Workflow

  • connect your API to mongo
  • define a schema
  • compile the schema into a model
  • create a mongoose document by instatiating (calling new on) a model
  • use the mongoose document to interact with the db document

Day 2

Review

  • what is mongoose?
  • what is a mongoose schema?
  • is mongoose a good fit for data that is dynamic (very little to no structure)?
  • if my database server address is: dbonline.com and my database name is zoodb, build a connection string using the default port (27017).
    • mongoose.connect('mongodb://dbonline.com/zoodb')
  • a MongoDB server can have many databases?
  • a JS object is stored inside MongoDB as a document?
  • a mongoose Schema compiles into a mongoose model?
  • a group of related documents is stored inside a collection?

Topics

  • quick tour of MongoDB Compass
  • finish CRUD endpoints
  • a look at supported data types

Day 3

Topics

  • importing data
  • modeling relations
    • one to one
    • one to many
    • many to many
  • embedded documents/schemas, AKA sub-documents
  • linking or refs
  • data population
  • querying data
    • sorting
    • projection
    • filtering

One to One: start with embedding (sub-documents)

  • One user has one profile.
  • One patient has one medical record.
  • One person has one Spouse.

One to many: start with a ref (linking)

  • most common type of relation
  • one order has many order lines.
  • one city has many citizens.

One to few: could be embedded or linked (ref).

  • a book can have more than one author.
  • an author can have many books.
  • a blog post have a few comments.

Many to Many(few)

  • books and authors
  • users and roles
  • departments and employees : one to many

Querying Data

let query = Character.find();

Character.find().sort('name') // by name ascending Character.find().sort('-name') // by name descending Character.find().sort('gender -height') // multiple fields Character.find().sort({ gender: 1, height: -1}) // multiple fields

Character.find().select('name gender') Character.find().select({name: 1, gender: 1}) Character.find().select({name: 1, gender: 1, _id: 0}) // excludes _id (it is always returned by default)

Character.find({ gender: 'female'}).sort('height').select('name').then().catch();

const gender = req.query.gender;

let query = Characters.find();

if (gender) {
  query.where({ gender: gender });
}

query.then(chars => res.json(chars)).catch();

query.where('age').gte(18).lte(62);

const express = require('express');
const Planet = require('./Planet.js');
const Character = require('../characters/Character');
const Species = require('../species/Specie');
const router = express.Router();
// add endpoints here
router.get('/:id', function(req, res) {
const { id } = req.params;
const chars = Character.find({ homeworld: id });
const species = Species.find({ homeworld: id });
Promise.all([chars, species])
.then(results => {
const [characters, species] = results;
res.status(200).json({ characters, species });
})
.catch(err => res.send(err));
});
module.exports = router;
const express = require('express');
const helmet = require('helmet');
const cors = require('cors');
const mongoose = require('mongoose');
// connect to mongo
mongoose
.connect('mongodb://localhost/beardb')
.then(mongo => {
console.log('connected to database');
})
.catch(err => {
console.log('Error connecting to database', err);
});
const bearController = require('./bears/bearController');
const server = express();
server.use(helmet());
server.use(cors());
server.use(express.json());
server.get('/', function(req, res) {
res.status(200).json({ api: 'running' });
});
server.use('/api/bears', bearController);
const port = process.env.PORT || 5000;
server.listen(port, () => {
console.log(`\n=== API running on http://localhost:${port} ===\n`);
});
const mongoose = require('mongoose');
const ObjectId = mongoose.Schema.Types.ObjectId;
const Specie = new mongoose.Schema({
edited: { type: Date, default: Date.now },
classification: String,
name: { type: String, required: true, index: true },
designation: String,
created: { type: Date, default: Date.now },
eye_colors: String,
people: [Number], // use this to populate the characters link as per readme
skin_colors: String,
language: String,
hair_colors: String,
average_lifespan: String,
average_height: String,
key: { type: Number, unique: true },
homeworld_key: Number,
// add homeworld field that links the specie to it's native planet
homeworld: {
type: ObjectId,
ref: 'Planet',
},
});
module.exports = mongoose.model('Specie', Specie);
const mongoose = require('mongoose');
const ObjectId = mongoose.Schema.Types.ObjectId;
const characterSchema = new mongoose.Schema({
name: {
type: String,
required: true,
index: true,
},
gender: String,
height: {
type: Number,
min: 0,
},
eye_color: String,
homeworld: {
type: ObjectId,
ref: 'Planet',
},
address: {
city: String,
state: String,
streetAddress: String,
},
});
const character = mongoose.model('Character', characterSchema);
const definition = {
starship_class: {
type: String,
required: true,
},
hyperdrive_rating: String,
key: Number,
pilots: [
{
type: ObjectId,
ref: 'Character',
},
],
};
const options = {
strict: false,
};
const starshipSchema = new mongoose.Schema(definition, options);
module.exports = mongoose.model('Starship', starshipSchema, 'starships');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment