Cheat Sheet
SQL + Postgres
SQL + Postgres Basics
Fullstack - refers to the combination of frontend (client-side) and backend (server-side) technologies.
PERN - an acronym for a specific set of technologies used to build a fullstack web application: Postgres, Express, React, and Node. This acronym is useful when asked "what stack do you use?"
Database - a structured collection of data that is organized in a manner for easy retrieval.
Database Management System (DBMS) - a piece of software used to create and maintain a database.
Postgres - a popular "relational" database management system that stores data in a table-like manner
SQL (Structured Query Language) - a language used by relational database management systems to create, read, update, or delete data from a database.

One-To-Many Table
Schema Design - the process of planning the structure and relationships of the tables in a database.
Primary Key - a column in a table that uniquely identifies each row in the table.
Foreign Key - a column in a table that references the primary key of another table.
One-to-Many - a relationship between two tables in which instances in one table can be referenced by many instances in another table.
JOIN- A SQL statement that combines the columns of two tables.
people Table:
1
Ann Duong
2
Reuben Ogbonna
3
Carmen Salas
4
Ben Spector
pets Table:
1
Khalo
dog
3
2
Juan Pablo
dog
2
3
Bora
bird
1
4
Frida
cat
3
5
Tora
dog
1
6
Pon Juablo
cat
2
7
Kora
dog
1
What are the names and ids of all the pets owned by Ann?
The order that you select
FROMandJOINdoes not matterThe
ONclause indicates the relationship between the two tables (thepets.owner_idcolumn references thepeople.idcolumn)The
WHEREclause filters down the result.When dealing with multiple tables, always specify the table that a value comes from.
Many To Many Table
Entity Relationship Diagram - a diagram that illustrates the relationships between tables.
Many-to-Many - a relationship between two tables in which the instances of each table can be referenced by many instances in the other table.
Association/Junction Table - a table used to create a many-to-many relationship using two foreign keys to reference two tables.

created using https://dbdiagram.io/
Q: Give me the names and ids of the customers that ordered product #2
pg
pgpg Basics
pg Basicspg— the official Node.js client library for PostgreSQL. It lets JavaScript code send SQL queries to and receive results from a Postgres database.Connection Pool — a cache of database connections reused across queries, rather than opening and closing a new connection for each query.
pool.query()— the primary method for sending a SQL query to the database. Returns a Promise that resolves to a result object.Result Object — the object resolved by
pool.query(). Its.rowsproperty is an array of matching records, each as a plain JavaScript object.Parameterized Query — a query where user-supplied values are passed separately from the SQL string using
$1,$2, etc. placeholders, preventing SQL injection.SQL Injection — a security attack where malicious SQL is embedded in user input and executed by the database. Parameterized queries prevent this.
.envfile — a file that stores environment variables (like database credentials) that should not be committed to version control.
Setting Up pool.js
pool.jsInstall
pganddotenv:Create a
.envfile in your project root:Never commit
.envto GitHub. Add it to.gitignore.Create
db/pool.jsthat sets up the pool once and exports it:
Running Queries with pool.query()
pool.query()pool.query()returns a Promise — alwaysawaitit inside anasyncfunction.result.rowsis an array of records. Each row is a plain JavaScript object.result.rowCountis the number of rows returned or affected.When no row matches,
result.rowsis[]— not an error.
Parameterized Queries
Never interpolate user input directly into a SQL string — it opens your app to SQL injection:
Use $1, $2, etc. placeholders and pass values in a separate array:
$1maps to the first element of the values array,$2to the second, and so on.Postgres treats the values as data only, never as SQL commands — even if they contain SQL syntax.
CRUD Operations with pg
pgRETURNING *makesINSERT,UPDATE, andDELETEreturn the affected row(s). Without it,result.rowsis empty.Use
result.rows[0]when you expect exactly one result (find, create, update, delete).Use
result.rowswhen you expect multiple results (list).
Async Model Methods
All pg queries are asynchronous. Every model method that calls pool.query() must be async and use await:
Model methods can wrap queries in try/catch to provide context on failure:
Async Controllers & Error Handling Middleware
Controllers that call async model methods must also be async. Use try/catch and pass errors to next(err):
Add an error handling middleware after all routes in index.js. Express identifies it by its four-parameter signature:
Authentication and Authorization
Authentication and Authorization Basics
Hashing - a mathematical algorithm that transforms a string of characters into a fixed-length string of characters.
Password Salt - A salt is a random string of data that is added to the input data before the hash function is applied. This changes the hash value that is produced, even for the same input data.
Salt Rounds - the number of times a password has been salted before being hashed
Plaintext password - the password as it was entered by the user, before it is hashed.
Bcrypt - a Node module that provides functions for hashing strings and verifying hashed strings.
Authentication - confirming who you are — verifying identity through login. Failure returns
401 Unauthorized.Authorization - confirming what you're allowed to do — checking permissions after identity is established. Failure returns
403 Forbidden.Session - a way for the server to persist information (like a logged-in user's ID) across multiple requests from the same client.
Cookie - a small piece of data set by a server and automatically sent by the browser with every subsequent request to that domain.
Bcrypt
The bcrypt module makes handling hashing, salting, and verification straightforward with two key methods:
bcrypt.hash(password, saltRounds)bcrypt.compare(password, hashedPassword)
We can create these helper functions to gracefully handle errors that can occur when using these asynchronous operations.
And when users want to create a new account or login to their existing account, we can use these functions for authentication:
Sessions with cookie-session
cookie-sessionHTTP is stateless — the server has no memory of previous requests. Sessions solve this by storing data (like the logged-in user's ID) that persists across requests.
cookie-session stores session data directly in an encrypted, signed cookie sent to the browser.
Install and configure it before your routes:
Add SESSION_SECRET to your .env file:
Once the middleware is in place, req.session is available in every controller:

Auth Endpoints
A complete authentication system has four endpoints:
POST
/api/register
Create a new user (hash password, store in DB)
POST
/api/login
Verify credentials, set session cookie
GET
/api/me
Return current user from session (or 401)
DELETE
/api/logout
Clear the session cookie
Login controller — find user, verify password, set session:
Use the same generic message for both "user not found" and "wrong password" — telling an attacker which one is true gives them information.
/api/me controller — return the current user from the session:
Logout controller — clear the session:
Authorization Middleware
checkAuthentication middleware protects routes that require login. It checks for a valid session and either continues the request or returns a 401:
Apply it to individual routes:
Or apply it to an entire router with router.use():
Ownership-Based Authorization
Being logged in is the first check. Some actions also require that the logged-in user owns the resource. Compare req.session.userId against the resource's owner field, returning 403 Forbidden if they don't match:
401 Unauthorized— "I don't know who you are. Log in."403 Forbidden— "I know who you are, but you can't do this."
Last updated