https://courses.wesbos.com/ | https://learnnode.com/ | https://github.com/wesbos/Learn-Node
Version: 20230101| Status: Completed
mongo --version
to see version. sudo mongod
to run MongoDB.env
, environmental variables, should never go to githubrouter.get(‘/reverse/:name’, (req, res) => { res.send(req.params.name); //e.g. /reverse/warren });
## Module 02.05 Core Concept - Templating
* pug is a templating language popular with node (used to be called Jade)
* Example code:
```javascript
//app.js
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug'); //pug, mustache, ejs work great
//routes/index.js
const router = express.Router();
router.get('/', (req, res) => {
res.render('hello'); //to render out hello.pug
//OR
res.render('hello', {
"dog": "Loki",
"name": req.param.name
}); //to render out hello.pug
});
//in .pug file, you can pass
//#{dog} or #{name} to reference
// pass variables to our templates + all requests
app.use((req, res, next) => {
res.locals.h = helpers;
res.locals.flashes = req.flash();
res.locals.user = req.user || null;
res.locals.currentPath = req.path;
next();
});
#{h.moment().endOf('day').fromNow()}
//index.js const express = require(‘express’); const router = express.Router(); const storeController = require(‘../controllers/storeController’);
routers.get(‘/’, storeController.homePage);
## Module 02.08 Core Concept - Middleware and Error Handling
* Middleware - fundamental to express - between the request and the response, e.g. in a Login, normalize/stanitize inputs, authorize user, etc. before Displaying Profile (success) or Login page (failed)
*
```javascript
//controllers/storeController
exports.myMiddleware = (req, res, next) => {
next();
}
exports.homePage = (req, res, next) => {
res.render('index');
}
//index.js
const express = require('express');
const router = express.Router();
const storeController = require('../controllers/storeController');
routers.get('/', storeConroller.myMiddleware, storeController.homePage);
//app.js
app.use(doSomething());
//any app.use is a middleware
const storeSchema = new mongoose.Schema({ name: { type: String, trim: true, required: ‘Please enter a store name!’ }, slug: String, description: { type: String, trim: true }, tags: [String] });
storeSchema.pre(‘save’, function(next) { if (!this.isModified(‘name’)) { next(); // skip it return; // stop this function from running //or return next(); } this.slug = slug(this.name); next(); // TODO make more resiliant so slugs are unique });
module.exports = mongoose.model(‘Store’, storeSchema);
//start.js //… //import all of our models require(‘./models/Store’); //…
## Module 03.10 Saving Stores and using Mixins
* [To summarize video] Adding a store. Create a .pug mixin for creating a store (using GET/POST)
* Mixin - pass in some data and it returns something to you
* Mongoose is a package used to interface with the MongoDB Database
## Module 04.11 Using Async Await
* You can't just "save the store and redirect" because JavaScript is Asynchronous. It won't wait - so you have to use await (in the past, used Callbacks).
* Wrap your async/await on a try/catch OR a middleware called catchErrors
* Example:
```javascript
//controllers/storeController.js
exports.createStore = async (req, res) => {
const store = new Store(req.body);
store
.save()
.then(store => {
return Store.find()
})
.then(store => {
return doSomething
})
.catch(error => {
throw Error(err)
})
};
//OR
//ES8
exports.createStore = async (req, res) => {
const store = new Store(req.body);
await store.save(); //need to do this line, before moving to the next
res.redirect(`/`);
//OR do this, which combines the who lines into a response, so you can call ${store.slug} later
const store = await (new Store(req.body)).save();
req.flash('success', `Successfully Created ${store.name}. Care to leave a review?`); //type of flash (e.g. success, warning, error, info)
res.redirect(`/store/${store.slug}`);
};
//routes/index.js
router.post('/add', catchErrors(storeController.createStore));
//controllers/storeController.js
exports.getStores = async (req, res) => {
// 1. Query the database for a list of all stores
const stores = await Store.find();
res.render('stores', { title: 'Stores', stores });
};
Edit ${store.name}
, store });
};exports.updateStore = async (req, res) => {
// find and update the store
const store = await Store.findOneAndUpdate({ _id: req.params.id }, req.body, {
new: true, // return the new store instead of the old one
runValidators: true
}).exec();
req.flash(‘success’, Successfully updated <strong>${store.name}</strong>. <a href="/stores/${store.slug}">View Store →</a>
);
res.redirect(/stores/${store._id}/edit
);
// Redirect them the store and tell them it worked
};
## Module 05.15 Saving Lat and Lng for each store
* Adding a Lat, Long for the database
## Module 05.16 Geocoding Data with Google Maps
* Use Google Maps API for Geolocation
## Module 05.17 Quick Data Visualization Tip
* Seeing the point in MongoDB
## Module 06.18 Uploading and Resizing Images with Middleware
* change form action to `enctype="multipart/form-data"`
* use package called `multer` for file upload middleware/upload request
## Module 06.19 Routing and Templating Single Stores
* rendering the store/page
## Module 07.20 Using Pre-Save hooks to make Unique Slugs
* deals with duplicate slugs
## Module 07.21 Custom MongoDB Aggregations
* Handle tags for store
## Module 07.22 Multiple Query Promises with Async:Await
* `await Promise.all([array_of_promises]);`
## Module 08.23 Creating User Accounts
## Module 08.24 Saving Registered Users to the Database
## Module 08.25 Virtual Fields, Login:Logout middleware and Protecting Routes
## Module 08.26 Creating a User Account Edit Screen
## Module 08.27 Password Reset Flow
## Module 09.28 Sending email with Nodejs
## Module 09.29 Locking down our application with User Permissions
## Module 10.30 Loading Sample Data
## Module 10.31 JSON endpoints and creating MongoDB Indexes
* Indexes make queries ahead of time and make queries faster
* Indexing will occur in Schema
* Create routes for API
* Example code with score and sorted:
```javascript
exports.searchStores = async (req, res) => {
const stores = await Store
// first find stores that match
.find({
$text: {
$search: req.query.q
}
}, {
score: { $meta: 'textScore' }
})
// the sort them
.sort({
score: { $meta: 'textScore' }
})
// limit to only 5 results
.limit(5);
res.json(stores);
};
dompurify
. dompurify.sanitize()
stuffexports.mapStores = async (req, res) => {
const coordinates = [req.query.lng, req.query.lat].map(parseFloat);
const q = {
location: {
$near: {
$geometry: {
type: 'Point',
coordinates
},
$maxDistance: 10000 // 10km
}
}
};
const stores = await Store.find(q).select('slug name description location photo').limit(10);
res.json(stores);
};
storeSchema.virtual
- kinda like a SQL join//models/Store.js
storeSchema.statics.getTopStores = function() {
return this.aggregate([
// Lookup Stores and populate their reviews
{ $lookup: { from: 'reviews', localField: '_id', foreignField: 'store', as: 'reviews' }},
// filter for only items that have 2 or more reviews
{ $match: { 'reviews.1': { $exists: true } } },
// Add the average reviews field
{ $project: {
photo: '$$ROOT.photo',
name: '$$ROOT.name',
reviews: '$$ROOT.reviews',
slug: '$$ROOT.slug',
averageRating: { $avg: '$reviews.rating' }
} },
// sort it by our new field, highest reviews first
{ $sort: { averageRating: -1 }},
// limit to at most 10
{ $limit: 10 }
]);
}
forever
package if something dropsforever start start.js
forever restart 0