Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 24 additions & 0 deletions Week3/3.1-normalization.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# 3.1 SQL Normalization

## 1. What columns violate 1NF?
- `food_code` and `food_description` columns contain multiple comma-separated values in a one cell and this is violates 1NF, to be presised - atomicity.
- `dinner_date` column has data in inconsistent formats and it is not strictly a 1NF violation but should be normalized for consistency purpose.

## 2. What entities do you recognize that could be extracted?
- member (member_id, member_name, member_address)
- dinner (dinner_id, dinner_date, venue_code)
- venue (venue_code, venue_description)
- food (food_code, food_description)
New tables, that can be created to properly model the relationships in normalized database. They are needed for a good design:
- dinner_food (dinner_id, food_code) — to represent which foods were served at each dinner
- member_dinner (member_id, dinner_id) — to represent which members attended which dinners

## 3. Name all the tables and columns that would make a 3NF compliant solution.
- members: (member_id PK, member_name, member_address)
- venues: (venue_code PK, venue_description)
- dinners: (dinner_id PK, dinner_date, venue_code FK)
- foods: (food_code PK, food_description)
- dinner_foods: (dinner_id FK, food_code FK, PK(dinner_id, food_code))
- member_dinners: (member_id FK, dinner_id FK, PK(member_id, dinner_id))


33 changes: 33 additions & 0 deletions Week3/3.3-sql-injection.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
## 1. Give an example of a malicious name and code value.

This function is vulnerable because it puts user input directly into the SQL string.

If somebody pass as `name`: `' OR 1=1 --`
And as `code`: `anything`
The query becomes:

```
SELECT Population FROM Country WHERE Name = '' OR 1=1 --' and code = 'anything'
```

And the -- makes the rest a comment, so it fetches all records.


## 2. Rewrite the function to use parameterized queries.
We need to use parameterized queries so user input is never directly inserted into the SQL string.

```
function getPopulation(Country, name, code, cb) {
conn.query(
`SELECT Population FROM ${Country} WHERE Name = $1 and code = $2`,
[name, code],
function (err, result) {
if (err) cb(err);
if (result.length == 0) cb(new Error("Not found"));
cb(null, result[0].Population);
}
);
}
```

This way, the database will treat name and code as values, not as part of the SQL code.
80 changes: 66 additions & 14 deletions Week3/homework/mongodb/index.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
require("dotenv").config({ path: "D:/HYF/databases-Cohort53/Week3/.env" });

const { MongoClient, ServerApiVersion } = require("mongodb");

const { seedDatabase } = require("./seedDatabase.js");
Expand All @@ -13,8 +15,29 @@ async function createEpisodeExercise(client) {

// Write code that will add this to the collection!

const collection = client.db("databaseWeek3").collection("bob_ross_episodes");
const newEpisode = {
episode: "S09E13",
title: "MOUNTAIN HIDE-AWAY",
elements: [
"CIRRUS",
"CLOUDS",
"CONIFER",
"DECIDIOUS",
"GRASS",
"MOUNTAIN",
"MOUNTAINS",
"RIVER",
"SNOWY_MOUNTAIN",
"TREE",
"TREES",
],
};

const result = await collection.insertOne(newEpisode);

console.log(
`Created season 9 episode 13 and the document got the id ${"TODO: fill in variable here"}`
`Created season 9 episode 13 and the document got the id ${result.insertedId}`
);
}

Expand All @@ -26,26 +49,36 @@ async function findEpisodesExercises(client) {

// Find the title of episode 2 in season 2 [Should be: WINTER SUN]

console.log(
`The title of episode 2 in season 2 is ${"TODO: fill in variable here"}`
);
const collection = client.db("databaseWeek3").collection("bob_ross_episodes");
const episodeTwo = await collection.findOne({ episode: "S02E02" });

console.log(`The title of episode 2 in season 2 is ${episodeTwo.title}`);

// Find the season and episode number of the episode called "BLACK RIVER" [Should be: S02E06]

const blackRiver = await collection.findOne({ title: "BLACK RIVER" });

console.log(
`The season and episode number of the "BLACK RIVER" episode is ${"TODO: fill in variable here"}`
`The season and episode number of the "BLACK RIVER" episode is ${blackRiver.episode}`
);

// Find all of the episode titles where Bob Ross painted a CLIFF [Should be: NIGHT LIGHT, EVENING SEASCAPE, SURF'S UP, CLIFFSIDE, BY THE SEA, DEEP WILDERNESS HOME, CRIMSON TIDE, GRACEFUL WATERFALL]
const cliffEpisodes = await collection.find({ elements: "CLIFF" }).toArray();
const cliffTitles = cliffEpisodes.map((episode) => episode.title).join(", ");

console.log(
`The episodes that Bob Ross painted a CLIFF are ${"TODO: fill in variable here"}`
);
console.log(`The episodes that Bob Ross painted a CLIFF are ${cliffTitles}`);

// Find all of the episode titles where Bob Ross painted a CLIFF and a LIGHTHOUSE [Should be: NIGHT LIGHT]

const lighthouseEpisodes = await collection
.find({ elements: { $all: ["CLIFF", "LIGHTHOUSE"] } })
.toArray();
const lighthouseTitles = lighthouseEpisodes
.map((episode) => episode.title)
.join(", ");

console.log(
`The episodes that Bob Ross painted a CLIFF and a LIGHTHOUSE are ${"TODO: fill in variable here"}`
`The episodes that Bob Ross painted a CLIFF and a LIGHTHOUSE are ${lighthouseTitles}`
);
}

Expand All @@ -58,17 +91,28 @@ async function updateEpisodeExercises(client) {
*/

// Episode 13 in season 30 should be called BLUE RIDGE FALLS, yet it is called BLUE RIDGE FALLERS now. Fix that
const collection = client.db("databaseWeek3").collection("bob_ross_episodes");

const updateResult = await collection.updateOne(
{ episode: "S30E13" },

{ $set: { title: "BLUE RIDGE FALLS" } }
);

console.log(
`Ran a command to update episode 13 in season 30 and it updated ${"TODO: fill in variable here"} episodes`
`Ran a command to update episode 13 in season 30 and it updated ${updateResult.modifiedCount} episodes`
);

// Unfortunately we made a mistake in the arrays and the element type called 'BUSHES' should actually be 'BUSH' as sometimes only one bush was painted.
// Update all of the documents in the collection that have `BUSHES` in the elements array to now have `BUSH`
// It should update 120 episodes!
const bushResult = await collection.updateMany(
{ elements: "BUSHES" },
{ $set: { "elements.$": "BUSH" } }
);

console.log(
`Ran a command to update all the BUSHES to BUSH and it updated ${"TODO: fill in variable here"} episodes`
`Ran a command to update all the BUSHES to BUSH and it updated ${bushResult.modifiedCount} episodes`
);
}

Expand All @@ -77,9 +121,12 @@ async function deleteEpisodeExercise(client) {
* It seems an errand episode has gotten into our data.
* This is episode 14 in season 31. Please remove it and verify that it has been removed!
*/
const collection = client.db("databaseWeek3").collection("bob_ross_episodes");

const deleteResult = await collection.deleteOne({ episode: "S31E14" });

console.log(
`Ran a command to delete episode and it deleted ${"TODO: fill in variable here"} episodes`
`Ran a command to delete episode and it deleted ${deleteResult.deletedCount} episodes`
);
}

Expand All @@ -89,15 +136,20 @@ async function main() {
`You did not set up the environment variables correctly. Did you create a '.env' file and add a package to create it?`
);
}

const client = new MongoClient(process.env.MONGODB_URL, {
useNewUrlParser: true,
useUnifiedTopology: true,
serverApi: ServerApiVersion.v1,
});

try {
await client.connect();

// creates a collection if it does'nt exist
const collection = client
.db("databaseWeek3")
.collection("bob_ross_episodes");
await collection.insertOne({ temp: true });

// Seed our database
await seedDatabase(client);

Expand Down
Loading