ref
and populate()
) the two schemas for the collections Books and Persons, much as JOIN
does in an SQL database between tables/src/app.js
)git init
.gitignore
npm init -y
"type": "module",
src/app.js
"start": "npx nodemon src/app.js"
npm i express ejs mongoose
import express from 'express';import path from 'path';
const app = express();const __dirname = path.resolve(path.dirname(''));const port = 3047;const staticDirectory = path.join(__dirname, './public');app.set('view engine', 'ejs');app.set('views', path.join(__dirname, './src/views'));app.use(express.static(staticDirectory));
app.listen(port, () => {console.log(`Now listening on port http://localhost:${port}`);});
npm start
app.get('/', async (req, res) => {res.send('testing');});
npm start
src/views/index.ejs
<html lang="en"><head><meta charset="UTF-8"><meta http-equiv="X-UA-Compatible"content="IE=edge"><meta name="viewport"content="width=device-width, initial-scale=1.0"><title>Tech Bookstore</title></head><body><h1>Tech Bookstore</h1></body></html>
res.render('index', {pageTitle: "Tech Bookstore"});
dev
folder and create these JSON files in itmongoimport --db bookstore --collection books --type json --file mongo.books.json --jsonArray
mongoimport --db bookstore --collection persons --type json --file mongo.persons.json --jsonArray
app.js
:import mongoose from 'mongoose';
mongoose.connect('mongodb://localhost:27017/bookstore');
src/models/persons.js
import mongoose from 'mongoose';const Schema = mongoose.Schema;const personsSchema = mongoose.Schema({firstName: String,lastName: String,email: String}, { collection: "persons" });const PersonsModel = mongoose.model("Person", personsSchema);export default PersonsModel;
src/models/books.js
import mongoose from 'mongoose';import PersonsModel from '../models/persons.js';const Schema = mongoose.Schema;const booksSchema = mongoose.Schema({title: String,author: { type: Schema.ObjectId, ref: 'Person' },url: String,customers: [{ type: Schema.ObjectId, ref: 'Person' }],isbn: String}, { collection: "books" });const BooksModel = mongoose.model("Book", booksSchema);export default BooksModel;
src/controllers/books.js
import BooksModel from '../models/books.js';export const getAllBooks = async () => {const books = await BooksModel.find({}).populate("author").populate("customers");return books;}
import * as BooksController from './controllers/books.js';
const books = await BooksController.getAllBooks();res.render('index', {pageTitle: "Tech Bookstore",books});
<p>there are <%=books.length%> books</p>
PersonsModel
even though VSCode indicates that it's not usedref: 'Person'
index.ejs
<% books.forEach(book=> { %><div class="book"><a href="<%=book.url%>" target="_blank"> <img src="images/<%=book.isbn%>.jpg"alt=""></a><div class="info"><div class="title"><%=book.title%></div><div class="author">by <span class="main"><%=book.author.firstName%><%=book.author.lastName%></span></div><ul class="customers"><div class="header">People who have bought this book:</div><% book.customers.forEach(customer=> { %><li><%=customer.firstName%><%=customer.lastName%><span class="email">(<%=customer.email%>)</span></li><% })%></ul></div></div><% });%>
public/images
public/css/main.scss
body {background-color: rgb(37, 3, 3);color: rgb(185, 183, 153);font-family: "Gill Sans", "Gill Sans MT", Calibri, "Trebuchet MS", sans-serif;font-size: 1.5rem;padding: 20px;div.book {background-color: rgb(71, 22, 22);margin: 0 0 20px 0;color: #ccc;padding: 20px;display: flex;img {width: 120px;box-shadow: 3px 3px 13px 3px #000000;}div.info {margin: 0 0 0 25px;}div.title {font-size: 1.8rem;}div.author {.main {font-size: 1.4rem;font-style: italic;color: rgb(235, 235, 154);}}ul.customers {color: #aaa;font-size: 0.9rem;li {margin: 0 0 0 -15px;font-style: italic;.email {color: #777;}}}div.header {margin: 0 0 4px -39px;}}}
index.ejs
add the link to the style sheet (to css/main.css
, not css/main.scss
!)<link rel="stylesheet" target="_blank" href="css/main.css">
import BooksModel from '../models/books.js';export const getAllBooks = async () => {const books = await BooksModel.find({}).populate("author").populate("customers").populate([{path: "comments",model: "Comment",select: "author message datetime",populate: {path: "author",model: "Person"}}]);return books;}