0% found this document useful (0 votes)
391 views

ALX Back End Storage

The document provides information about advanced MySQL concepts including stored procedures, triggers, views, functions, operators and syntax. It also includes requirements and instructions for completing tasks to demonstrate skills with MySQL tables, constraints, indexes, procedures and other features.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
391 views

ALX Back End Storage

The document provides information about advanced MySQL concepts including stored procedures, triggers, views, functions, operators and syntax. It also includes requirements and instructions for completing tasks to demonstrate skills with MySQL tables, constraints, indexes, procedures and other features.
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 56

Back-end - Storage

0x00. MySQL advanced


Back-endSQLMySQL

By: Guillaume Plessis, Senior Cloud & System Engineer at WeWork and
Guillaume, CTO at Holberton school

Weight: 1

Project over - took place from Feb 8, 2023 5:00 AM to Feb 10, 2023 5:00 AM

An auto review will be launched at the deadline

In a nutshell…
Auto QA review: 53.0/53 mandatory & 8.0/8 optional

Altogether: 200.0%

Mandatory: 100.0%

Optional: 100.0%

Calculation: 100.0% + (100.0% * 100.0%) == 200.0%

Concepts

Advanced SQL

MySQL cheatsheet

MySQL Performance: How To Leverage MySQL Database Indexing

Stored Procedure

Triggers

Views

Functions and Operators

Trigger Syntax and Examples

CREATE TABLE Statement

CREATE PROCEDURE and CREATE FUNCTION Statements

CREATE INDEX Statement

Back-end - Storage 1
CREATE VIEW Statement

Resources
Read or watch:

MySQL cheatsheet

MySQL Performance: How To Leverage MySQL Database Indexing

Stored Procedure

Triggers

Views

Functions and Operators

Trigger Syntax and Examples

CREATE TABLE Statement

CREATE PROCEDURE and CREATE FUNCTION Statements

CREATE INDEX Statement

CREATE VIEW Statement

Learning Objectives
At the end of this project, you are expected to be able to explain to anyone, without
the help of Google:

General
How to create tables with constraints

How to optimize queries by adding indexes

What is and how to implement stored procedures and functions in MySQL

What is and how to implement views in MySQL

What is and how to implement triggers in MySQL

Requirements

Back-end - Storage 2
General
All your files will be executed on Ubuntu 18.04 LTS using MySQL 5.7 (version
5.7.30)

All your files should end with a new line

All your SQL queries should have a comment just before (i.e. syntax above)

All your files should start by a comment describing the task

All SQL keywords should be in uppercase ( SELECT , WHERE …)

A README.md file, at the root of the folder of the project, is mandatory

The length of your files will be tested using wc

More Info

Comments for your SQL file:


$ cat my_script.sql
-- 3 first students in the Batch ID=3
-- because Batch 3 is the best!
SELECT id, name FROM students WHERE batch_id = 3 ORDER BY created_at DESC LIMIT 3;
$

Use “container-on-demand” to run MySQL


Ask for container Ubuntu 18.04 - Python 3.7

Connect via SSH

Or via the WebTerminal

In the container, you should start MySQL before playing with it:

$ service mysql start


* MySQL Community Server 5.7.30 is started
$
$ cat 0-list_databases.sql | mysql -uroot -p my_database
Enter password:
Database
information_schema
mysql

Back-end - Storage 3
performance_schema
sys
$

In the container, credentials are root/root

How to import a SQL dump


$ echo "CREATE DATABASE hbtn_0d_tvshows;" | mysql -uroot -p
Enter password:
$ curl "https://s3.amazonaws.com/intranet-projects-files/holbertonschool-higher-level_
programming+/274/hbtn_0d_tvshows.sql" -s | mysql -uroot -p hbtn_0d_tvshows
Enter password:
$ echo "SELECT * FROM tv_genres" | mysql -uroot -p hbtn_0d_tvshows
Enter password:
id name
1 Drama
2 Mystery
3 Adventure
4 Fantasy
5 Comedy
6 Crime
7 Suspense
8 Thriller
$

Tasks
0. We are all unique!
mandatory
Score: 100.0% (Checks completed: 100.0%)
Write a SQL script that creates a table users following these requirements:

With these attributes:

id , integer, never null, auto increment and primary key

email , string (255 characters), never null and unique

name , string (255 characters)

If the table already exists, your script should not fail

Your script can be executed on any database

Back-end - Storage 4
Context: Make an attribute unique directly in the table schema will enforced your
business rules and avoid bugs in your application

bob@dylan:~$ echo "SELECT * FROM users;" | mysql -uroot -p holberton


Enter password:
ERROR 1146 (42S02) at line 1: Table 'holberton.users' doesn't exist
bob@dylan:~$
bob@dylan:~$ cat 0-uniq_users.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ echo 'INSERT INTO users (email, name) VALUES ("[email protected]", "Bob");' |
mysql -uroot -p holberton
Enter password:
bob@dylan:~$ echo 'INSERT INTO users (email, name) VALUES ("[email protected]", "Sylvi
e");' | mysql -uroot -p holberton
Enter password:
bob@dylan:~$ echo 'INSERT INTO users (email, name) VALUES ("[email protected]", "Jean");'
| mysql -uroot -p holberton
Enter password:
ERROR 1062 (23000) at line 1: Duplicate entry '[email protected]' for key 'email'
bob@dylan:~$
bob@dylan:~$ echo "SELECT * FROM users;" | mysql -uroot -p holberton
Enter password:
id email name
1 [email protected] Bob
2 [email protected] Sylvie
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 0-uniq_users.sql

Done! Help Check your code Get a sandbox QA Review

1. In and not out


mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a SQL script that creates a table users following these requirements:

With these attributes:

id , integer, never null, auto increment and primary key

email , string (255 characters), never null and unique

Back-end - Storage 5
name , string (255 characters)

, enumeration of countries: US , CO and TN , never null (= default will


country

be the first element of the enumeration, here US )

If the table already exists, your script should not fail

Your script can be executed on any database

bob@dylan:~$ echo "SELECT * FROM users;" | mysql -uroot -p holberton


Enter password:
ERROR 1146 (42S02) at line 1: Table 'holberton.users' doesn't exist
bob@dylan:~$
bob@dylan:~$ cat 1-country_users.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ echo 'INSERT INTO users (email, name, country) VALUES ("[email protected]",
"Bob", "US");' | mysql -uroot -p holberton
Enter password:
bob@dylan:~$ echo 'INSERT INTO users (email, name, country) VALUES ("[email protected]
m", "Sylvie", "CO");' | mysql -uroot -p holberton
Enter password:
bob@dylan:~$ echo 'INSERT INTO users (email, name, country) VALUES ("[email protected]",
"Jean", "FR");' | mysql -uroot -p holberton
Enter password:
ERROR 1265 (01000) at line 1: Data truncated for column 'country' at row 1
bob@dylan:~$
bob@dylan:~$ echo 'INSERT INTO users (email, name) VALUES ("[email protected]", "John");'
| mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ echo "SELECT * FROM users;" | mysql -uroot -p holberton
Enter password:
id email name country
1 [email protected] Bob US
2 [email protected] Sylvie CO
3 [email protected] John US
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 1-country_users.sql

Done! Help Check your code Get a sandbox QA Review

2. Best band ever!


mandatory

Back-end - Storage 6
Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that ranks country origins of bands, ordered by the number of
(non-unique) fans
Requirements:

Import this table dump: metal_bands.sql.zip

Column names must be: origin and nb_fans

Your script can be executed on any database

Context: Calculate/compute something is always power intensive… better to


distribute the load!

bob@dylan:~$ cat metal_bands.sql | mysql -uroot -p holberton


Enter password:
bob@dylan:~$
bob@dylan:~$ cat 2-fans.sql | mysql -uroot -p holberton > tmp_res ; head tmp_res
Enter password:
origin nb_fans
USA 99349
Sweden 47169
Finland 32878
United Kingdom 32518
Germany 29486
Norway 22405
Canada 8874
The Netherlands 8819
Italy 7178
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 2-fans.sql

Done! Help Check your code Get a sandbox QA Review

3. Old school band


mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that lists all bands with Glam rock as their main style, ranked by
their longevity

Back-end - Storage 7
Requirements:

Import this table dump: metal_bands.sql.zip

Column names must be: band_name and lifespan (in years until 2022 - please
use 2022 instead of YEAR(CURDATE()) )

You should use attributes formed and split for computing the lifespan

Your script can be executed on any database

bob@dylan:~$ cat metal_bands.sql | mysql -uroot -p holberton


Enter password:
bob@dylan:~$
bob@dylan:~$ cat 3-glam_rock.sql | mysql -uroot -p holberton
Enter password:
band_name lifespan
Alice Cooper 56
Mötley Crüe 34
Marilyn Manson 31
The 69 Eyes 30
Hardcore Superstar 23
Nasty Idols 0
Hanoi Rocks 0
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 3-glam_rock.sql

Done! Help Check your code Get a sandbox QA Review

4. Buy buy buy


mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that creates a trigger that decreases the quantity of an item after
adding a new order.

Quantity in the table items can be negative.


Context: Updating multiple tables for one action from your application can generate
issue: network disconnection, crash, etc… to keep your data in a good shape, let
MySQL do it for you!

Back-end - Storage 8
bob@dylan:~$ cat 4-init.sql
-- Initial
DROP TABLE IF EXISTS items;
DROP TABLE IF EXISTS orders;

CREATE TABLE IF NOT EXISTS items (


name VARCHAR(255) NOT NULL,
quantity int NOT NULL DEFAULT 10
);

CREATE TABLE IF NOT EXISTS orders (


item_name VARCHAR(255) NOT NULL,
number int NOT NULL
);

INSERT INTO items (name) VALUES ("apple"), ("pineapple"), ("pear");

bob@dylan:~$
bob@dylan:~$ cat 4-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 4-store.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 4-main.sql
Enter password:
-- Show and add orders
SELECT * FROM items;
SELECT * FROM orders;

INSERT INTO orders (item_name, number) VALUES ('apple', 1);


INSERT INTO orders (item_name, number) VALUES ('apple', 3);
INSERT INTO orders (item_name, number) VALUES ('pear', 2);

SELECT "--";

SELECT * FROM items;


SELECT * FROM orders;

bob@dylan:~$
bob@dylan:~$ cat 4-main.sql | mysql -uroot -p holberton
Enter password:
name quantity
apple 10
pineapple 10
pear 10
--
--
name quantity
apple 6
pineapple 10
pear 8
item_name number
apple 1
apple 3

Back-end - Storage 9
pear 2
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 4-store.sql

Done! Help Check your code Get a sandbox QA Review

5. Email validation to sent


mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that creates a trigger that resets the attribute valid_email only
when the email has been changed.

Context: Nothing related to MySQL, but perfect for user email validation - distribute
the logic to the database itself!

bob@dylan:~$ cat 5-init.sql


-- Initial
DROP TABLE IF EXISTS users;

CREATE TABLE IF NOT EXISTS users (


id int not null AUTO_INCREMENT,
email varchar(255) not null,
name varchar(255),
valid_email boolean not null default 0,
PRIMARY KEY (id)
);

INSERT INTO users (email, name) VALUES ("[email protected]", "Bob");


INSERT INTO users (email, name, valid_email) VALUES ("[email protected]", "Sylvie", 1);
INSERT INTO users (email, name, valid_email) VALUES ("[email protected]", "Jeanne", 1);

bob@dylan:~$
bob@dylan:~$ cat 5-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 5-valid_email.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 5-main.sql
Enter password:
-- Show users and update (or not) email
SELECT * FROM users;

Back-end - Storage 10
UPDATE users SET valid_email = 1 WHERE email = "[email protected]";
UPDATE users SET email = "[email protected]" WHERE email = "[email protected]";
UPDATE users SET name = "Jannis" WHERE email = "[email protected]";

SELECT "--";
SELECT * FROM users;

UPDATE users SET email = "[email protected]" WHERE email = "[email protected]";

SELECT "--";
SELECT * FROM users;

bob@dylan:~$
bob@dylan:~$ cat 5-main.sql | mysql -uroot -p holberton
Enter password:
id email name valid_email
1 [email protected] Bob 0
2 [email protected] Sylvie 1
3 [email protected] Jeanne 1
--
--
id email name valid_email
1 [email protected] Bob 1
2 [email protected] Sylvie 0
3 [email protected] Jannis 1
--
--
id email name valid_email
1 [email protected] Bob 1
2 [email protected] Sylvie 0
3 [email protected] Jannis 1
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 5-valid_email.sql

Done! Help Check your code Get a sandbox QA Review

6. Add bonus
mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that creates a stored procedure AddBonus that adds a new
correction for a student.
Requirements:

Back-end - Storage 11
Procedure AddBonus is taking 3 inputs (in this order):

user_id ,a users.id value (you can assume user_id is linked to an


existing users )

project_name, a new or already exists projects - if no projects.name found in


the table, you should create it

score , the score value for the correction

Context: Write code in SQL is a nice level up!

bob@dylan:~$ cat 6-init.sql


-- Initial
DROP TABLE IF EXISTS corrections;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS projects;

CREATE TABLE IF NOT EXISTS users (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
average_score float default 0,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS projects (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS corrections (


user_id int not null,
project_id int not null,
score int default 0,
KEY `user_id` (`user_id`),
KEY `project_id` (`project_id`),
CONSTRAINT fk_user_id FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE
CASCADE,
CONSTRAINT fk_project_id FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) O
N DELETE CASCADE
);

INSERT INTO users (name) VALUES ("Bob");


SET @user_bob = LAST_INSERT_ID();

INSERT INTO users (name) VALUES ("Jeanne");


SET @user_jeanne = LAST_INSERT_ID();

INSERT INTO projects (name) VALUES ("C is fun");


SET @project_c = LAST_INSERT_ID();

INSERT INTO projects (name) VALUES ("Python is cool");


SET @project_py = LAST_INSERT_ID();

Back-end - Storage 12
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_c, 8
0);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_py, 9
6);

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_c,


91);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_p
y, 73);

bob@dylan:~$
bob@dylan:~$ cat 6-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 6-bonus.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 6-main.sql
Enter password:
-- Show and add bonus correction
SELECT * FROM projects;
SELECT * FROM corrections;

SELECT "--";

CALL AddBonus((SELECT id FROM users WHERE name = "Jeanne"), "Python is cool", 100);

CALL AddBonus((SELECT id FROM users WHERE name = "Jeanne"), "Bonus project", 100);
CALL AddBonus((SELECT id FROM users WHERE name = "Bob"), "Bonus project", 10);

CALL AddBonus((SELECT id FROM users WHERE name = "Jeanne"), "New bonus", 90);

SELECT "--";

SELECT * FROM projects;


SELECT * FROM corrections;

bob@dylan:~$
bob@dylan:~$ cat 6-main.sql | mysql -uroot -p holberton
Enter password:
id name
1 C is fun
2 Python is cool
user_id project_id score
1 1 80
1 2 96
2 1 91
2 2 73
--
--
--
--
id name
1 C is fun
2 Python is cool
3 Bonus project
4 New bonus

Back-end - Storage 13
user_id project_id score
1 1 80
1 2 96
2 1 91
2 2 73
2 2 100
2 3 100
1 3 10
2 4 90
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 6-bonus.sql

Done! Help Check your code Get a sandbox QA Review

7. Average score
mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that creates a stored procedure ComputeAverageScoreForUser that


computes and store the average score for a student. Note: An average score can be
a decimal
Requirements:

Procedure ComputeAverageScoreForUser is taking 1 input:

user_id ,a users.id value (you can assume user_id is linked to an


existing users )

bob@dylan:~$ cat 7-init.sql


-- Initial
DROP TABLE IF EXISTS corrections;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS projects;

CREATE TABLE IF NOT EXISTS users (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
average_score float default 0,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS projects (

Back-end - Storage 14
id int not null AUTO_INCREMENT,
name varchar(255) not null,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS corrections (


user_id int not null,
project_id int not null,
score int default 0,
KEY `user_id` (`user_id`),
KEY `project_id` (`project_id`),
CONSTRAINT fk_user_id FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE
CASCADE,
CONSTRAINT fk_project_id FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) O
N DELETE CASCADE
);

INSERT INTO users (name) VALUES ("Bob");


SET @user_bob = LAST_INSERT_ID();

INSERT INTO users (name) VALUES ("Jeanne");


SET @user_jeanne = LAST_INSERT_ID();

INSERT INTO projects (name) VALUES ("C is fun");


SET @project_c = LAST_INSERT_ID();

INSERT INTO projects (name) VALUES ("Python is cool");


SET @project_py = LAST_INSERT_ID();

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_c, 8


0);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_py, 9
6);

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_c,


91);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_p
y, 73);

bob@dylan:~$
bob@dylan:~$ cat 7-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 7-average_score.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 7-main.sql
-- Show and compute average score
SELECT * FROM users;
SELECT * FROM corrections;

SELECT "--";
CALL ComputeAverageScoreForUser((SELECT id FROM users WHERE name = "Jeanne"));

SELECT "--";
SELECT * FROM users;

Back-end - Storage 15
bob@dylan:~$
bob@dylan:~$ cat 7-main.sql | mysql -uroot -p holberton
Enter password:
id name average_score
1 Bob 0
2 Jeanne 0
user_id project_id score
1 1 80
1 2 96
2 1 91
2 2 73
--
--
--
--
id name average_score
1 Bob 0
2 Jeanne 82
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 7-average_score.sql

Done! Help Check your code Get a sandbox QA Review

8. Optimize simple search


mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a SQL script that creates an index idx_name_first on the table names and the
first letter of name .

Requirements:

Import this table dump: names.sql.zip

Only the first letter of name must be indexed

Context: Index is not the solution for any performance issue, but well used, it’s really
powerful!

bob@dylan:~$ cat names.sql | mysql -uroot -p holberton


Enter password:
bob@dylan:~$
bob@dylan:~$ mysql -uroot -p holberton

Back-end - Storage 16
Enter password:
mysql> SELECT COUNT(name) FROM names WHERE name LIKE 'a%';
+-------------+
| COUNT(name) |
+-------------+
| 302936 |
+-------------+
1 row in set (2.19 sec)
mysql>
mysql> exit
bye
bob@dylan:~$
bob@dylan:~$ cat 8-index_my_names.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ mysql -uroot -p holberton
Enter password:
mysql> SHOW index FROM names;
+-------+------------+----------------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation | Cardi
nality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
| names | 1 | idx_name_first | 1 | name | A |
25 | 1 | NULL | YES | BTREE | | |
+-------+------------+----------------+--------------+-------------+-----------+------
-------+----------+--------+------+------------+---------+---------------+
1 row in set (0.00 sec)
mysql>
mysql> SELECT COUNT(name) FROM names WHERE name LIKE 'a%';
+-------------+
| COUNT(name) |
+-------------+
| 302936 |
+-------------+
1 row in set (0.82 sec)
mysql>
mysql> exit
bye
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 8-index_my_names.sql

Done! Help Check your code Get a sandbox QA Review

9. Optimize search and score


mandatory

Back-end - Storage 17
Score: 100.0% (Checks completed: 100.0%)
Write a SQL script that creates an index idx_name_first_score on the table names and
the first letter of name and the score .
Requirements:

Import this table dump: names.sql.zip

Only the first letter of name AND score must be indexed

bob@dylan:~$ cat names.sql | mysql -uroot -p holberton


Enter password:
bob@dylan:~$
bob@dylan:~$ mysql -uroot -p holberton
Enter password:
mysql> SELECT COUNT(name) FROM names WHERE name LIKE 'a%' AND score < 80;
+-------------+
| count(name) |
+-------------+
| 60717 |
+-------------+
1 row in set (2.40 sec)
mysql>
mysql> exit
bye
bob@dylan:~$
bob@dylan:~$ cat 9-index_name_score.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ mysql -uroot -p holberton
Enter password:
mysql> SHOW index FROM names;
+-------+------------+----------------------+--------------+-------------+-----------+
-------------+----------+--------+------+------------+---------+---------------+
| Table | Non_unique | Key_name | Seq_in_index | Column_name | Collation |
Cardinality | Sub_part | Packed | Null | Index_type | Comment | Index_comment |
+-------+------------+----------------------+--------------+-------------+-----------+
-------------+----------+--------+------+------------+---------+---------------+
| names | 1 | idx_name_first_score | 1 | name | A |
25 | 1 | NULL | YES | BTREE | | |
| names | 1 | idx_name_first_score | 2 | score | A |
3901 | NULL | NULL | YES | BTREE | | |
+-------+------------+----------------------+--------------+-------------+-----------+
-------------+----------+--------+------+------------+---------+---------------+
2 rows in set (0.00 sec)
mysql>
mysql> SELECT COUNT(name) FROM names WHERE name LIKE 'a%' AND score < 80;
+-------------+
| COUNT(name) |
+-------------+
| 60717 |
+-------------+
1 row in set (0.48 sec)
mysql>

Back-end - Storage 18
mysql> exit
bye
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 9-index_name_score.sql

Done! Help Check your code Get a sandbox QA Review

10. Safe divide


mandatory
Score: 100.0% (Checks completed: 100.0%)
Write a SQL script that creates a function SafeDiv that divides (and returns) the first
by the second number or returns 0 if the second number is equal to 0.
Requirements:

You must create a function

The function SafeDiv takes 2 arguments:

a , INT

b , INT

And returns a / b or 0 if b == 0

bob@dylan:~$ cat 10-init.sql


-- Initial
DROP TABLE IF EXISTS numbers;

CREATE TABLE IF NOT EXISTS numbers (


a int default 0,
b int default 0
);

INSERT INTO numbers (a, b) VALUES (10, 2);


INSERT INTO numbers (a, b) VALUES (4, 5);
INSERT INTO numbers (a, b) VALUES (2, 3);
INSERT INTO numbers (a, b) VALUES (6, 3);
INSERT INTO numbers (a, b) VALUES (7, 0);
INSERT INTO numbers (a, b) VALUES (6, 8);

bob@dylan:~$ cat 10-init.sql | mysql -uroot -p holberton


Enter password:

Back-end - Storage 19
bob@dylan:~$
bob@dylan:~$ cat 10-div.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ echo "SELECT (a / b) FROM numbers;" | mysql -uroot -p holberton
Enter password:
(a / b)
5.0000
0.8000
0.6667
2.0000
NULL
0.7500
bob@dylan:~$
bob@dylan:~$ echo "SELECT SafeDiv(a, b) FROM numbers;" | mysql -uroot -p holberton
Enter password:
SafeDiv(a, b)
5
0.800000011920929
0.6666666865348816
2
0
0.75
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 10-div.sql

Done! Help Check your code Get a sandbox QA Review

11. No table for a meeting


mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a SQL script that creates a view need_meeting that lists all students that have a
score under 80 (strict) and no last_meeting or more than 1 month.
Requirements:

The view need_meeting should return all students name when:

They score are under (strict) to 80

AND no last_meeting date OR more than a month

Back-end - Storage 20
bob@dylan:~$ cat 11-init.sql
-- Initial
DROP TABLE IF EXISTS students;

CREATE TABLE IF NOT EXISTS students (


name VARCHAR(255) NOT NULL,
score INT default 0,
last_meeting DATE NULL
);

INSERT INTO students (name, score) VALUES ("Bob", 80);


INSERT INTO students (name, score) VALUES ("Sylvia", 120);
INSERT INTO students (name, score) VALUES ("Jean", 60);
INSERT INTO students (name, score) VALUES ("Steeve", 50);
INSERT INTO students (name, score) VALUES ("Camilia", 80);
INSERT INTO students (name, score) VALUES ("Alexa", 130);

bob@dylan:~$ cat 11-init.sql | mysql -uroot -p holberton


Enter password:
bob@dylan:~$
bob@dylan:~$ cat 11-need_meeting.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 11-main.sql
-- Test view
SELECT * FROM need_meeting;

SELECT "--";

UPDATE students SET score = 40 WHERE name = 'Bob';


SELECT * FROM need_meeting;

SELECT "--";

UPDATE students SET score = 80 WHERE name = 'Steeve';


SELECT * FROM need_meeting;

SELECT "--";

UPDATE students SET last_meeting = CURDATE() WHERE name = 'Jean';


SELECT * FROM need_meeting;

SELECT "--";

UPDATE students SET last_meeting = ADDDATE(CURDATE(), INTERVAL -2 MONTH) WHERE name =


'Jean';
SELECT * FROM need_meeting;

SELECT "--";

SHOW CREATE TABLE need_meeting;

SELECT "--";

SHOW CREATE TABLE students;

Back-end - Storage 21
bob@dylan:~$
bob@dylan:~$ cat 11-main.sql | mysql -uroot -p holberton
Enter password:
name
Jean
Steeve
--
--
name
Bob
Jean
Steeve
--
--
name
Bob
Jean
--
--
name
Bob
--
--
name
Bob
Jean
--
--
View Create View character_set_client collation_connection
XXXXXX<yes, here it will display the View SQL statement :-) >XXXXXX
--
--
Table Create Table
students CREATE TABLE `students` (\n `name` varchar(255) NOT NULL,\n `score` int
(11) DEFAULT '0',\n `last_meeting` date DEFAULT NULL\n) ENGINE=InnoDB DEFAULT CHARSET
=latin1
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 11-need_meeting.sql

Done! Help Check your code Get a sandbox QA Review

12. Average weighted score


#advanced
Score: 100.0% (Checks completed: 100.0%)

Back-end - Storage 22
Write a SQL script that creates a stored
procedure ComputeAverageWeightedScoreForUser that computes and store the average
weighted score for a student.

Requirements:

Procedure ComputeAverageScoreForUser is taking 1 input:

user_id ,a users.id value (you can assume user_id is linked to an


existing users )

Tips:

Calculate-Weighted-Average

bob@dylan:~$ cat 100-init.sql


-- Initial
DROP TABLE IF EXISTS corrections;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS projects;

CREATE TABLE IF NOT EXISTS users (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
average_score float default 0,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS projects (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
weight int default 1,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS corrections (


user_id int not null,
project_id int not null,
score float default 0,
KEY `user_id` (`user_id`),
KEY `project_id` (`project_id`),
CONSTRAINT fk_user_id FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE
CASCADE,
CONSTRAINT fk_project_id FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) O
N DELETE CASCADE
);

INSERT INTO users (name) VALUES ("Bob");


SET @user_bob = LAST_INSERT_ID();

INSERT INTO users (name) VALUES ("Jeanne");


SET @user_jeanne = LAST_INSERT_ID();

INSERT INTO projects (name, weight) VALUES ("C is fun", 1);

Back-end - Storage 23
SET @project_c = LAST_INSERT_ID();

INSERT INTO projects (name, weight) VALUES ("Python is cool", 2);


SET @project_py = LAST_INSERT_ID();

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_c, 8


0);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_py, 9
6);

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_c,


91);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_p
y, 73);

bob@dylan:~$
bob@dylan:~$ cat 100-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 100-average_weighted_score.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 100-main.sql
-- Show and compute average weighted score
SELECT * FROM users;
SELECT * FROM projects;
SELECT * FROM corrections;

CALL ComputeAverageWeightedScoreForUser((SELECT id FROM users WHERE name = "Jeanne"));

SELECT "--";
SELECT * FROM users;

bob@dylan:~$
bob@dylan:~$ cat 100-main.sql | mysql -uroot -p holberton
Enter password:
id name average_score
1 Bob 0
2 Jeanne 82
id name weight
1 C is fun 1
2 Python is cool 2
user_id project_id score
1 1 80
1 2 96
2 1 91
2 2 73
--
--
id name average_score
1 Bob 0
2 Jeanne 79
bob@dylan:~$

Repo:

Back-end - Storage 24
GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 100-average_weighted_score.sql

Done! Help Check your code Get a sandbox QA Review

13. Average weighted score for all!


#advanced

Score: 100.0% (Checks completed: 100.0%)


Write a SQL script that creates a stored
procedure ComputeAverageWeightedScoreForUsers that computes and store the average
weighted score for all students.
Requirements:

Procedure ComputeAverageWeightedScoreForUsers is not taking any input.

Tips:

Calculate-Weighted-Average

bob@dylan:~$ cat 101-init.sql


-- Initial
DROP TABLE IF EXISTS corrections;
DROP TABLE IF EXISTS users;
DROP TABLE IF EXISTS projects;

CREATE TABLE IF NOT EXISTS users (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
average_score float default 0,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS projects (


id int not null AUTO_INCREMENT,
name varchar(255) not null,
weight int default 1,
PRIMARY KEY (id)
);

CREATE TABLE IF NOT EXISTS corrections (


user_id int not null,
project_id int not null,
score float default 0,
KEY `user_id` (`user_id`),
KEY `project_id` (`project_id`),
CONSTRAINT fk_user_id FOREIGN KEY (`user_id`) REFERENCES `users` (`id`) ON DELETE
CASCADE,

Back-end - Storage 25
CONSTRAINT fk_project_id FOREIGN KEY (`project_id`) REFERENCES `projects` (`id`) O
N DELETE CASCADE
);

INSERT INTO users (name) VALUES ("Bob");


SET @user_bob = LAST_INSERT_ID();

INSERT INTO users (name) VALUES ("Jeanne");


SET @user_jeanne = LAST_INSERT_ID();

INSERT INTO projects (name, weight) VALUES ("C is fun", 1);


SET @project_c = LAST_INSERT_ID();

INSERT INTO projects (name, weight) VALUES ("Python is cool", 2);


SET @project_py = LAST_INSERT_ID();

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_c, 8


0);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_bob, @project_py, 9
6);

INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_c,


91);
INSERT INTO corrections (user_id, project_id, score) VALUES (@user_jeanne, @project_p
y, 73);

bob@dylan:~$
bob@dylan:~$ cat 101-init.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 101-average_weighted_score.sql | mysql -uroot -p holberton
Enter password:
bob@dylan:~$
bob@dylan:~$ cat 101-main.sql
-- Show and compute average weighted score
SELECT * FROM users;
SELECT * FROM projects;
SELECT * FROM corrections;

CALL ComputeAverageWeightedScoreForUsers();

SELECT "--";
SELECT * FROM users;

bob@dylan:~$
bob@dylan:~$ cat 101-main.sql | mysql -uroot -p holberton
Enter password:
id name average_score
1 Bob 0
2 Jeanne 0
id name weight
1 C is fun 1
2 Python is cool 2
user_id project_id score
1 1 80
1 2 96
2 1 91

Back-end - Storage 26
2 2 73
--
--
id name average_score
1 Bob 90.6667
2 Jeanne 79
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x00-MySQL_Advanced

File: 101-average_weighted_score.sql

0x01. NoSQL
Back-endNoSQLMongoDB

By: Emmanuel Turlay, Staff Software Engineer at Cruise and Guillaume, CTO at
Holberton school

Weight: 1

Project over - took place from Feb 13, 2023 5:00 AM to Feb 15, 2023 5:00 AM

An auto review will be launched at the deadline

In a nutshell…
Auto QA review: 133.95/135 mandatory & 32.0/32 optional

Altogether: 198.44%

Mandatory: 99.22%

Optional: 100.0%

Calculation: 99.22% + (99.22% * 100.0%) == 198.44%

Resources
Read or watch:

NoSQL Databases Explained

Back-end - Storage 27
What is NoSQL ?

MongoDB with Python Crash Course - Tutorial for Beginners

MongoDB Tutorial 2 : Insert, Update, Remove, Query

Aggregation

Introduction to MongoDB and Python

mongo Shell Methods

The mongo Shell

Learning Objectives
At the end of this project, you are expected to be able to explain to anyone, without
the help of Google:

General
What NoSQL means

What is difference between SQL and NoSQL

What is ACID

What is a document storage

What are NoSQL types

What are benefits of a NoSQL database

How to query information from a NoSQL database

How to insert/update/delete information from a NoSQL database

How to use MongoDB

Requirements

MongoDB Command File


All your files will be interpreted/compiled on Ubuntu 18.04 LTS
using MongoDB (version 4.2)

Back-end - Storage 28
All your files should end with a new line

The first line of all your files should be a comment: // my comment

A README.md file, at the root of the folder of the project, is mandatory

The length of your files will be tested using wc

Python Scripts
All your files will be interpreted/compiled on Ubuntu 18.04 LTS
using python3 (version 3.7) and PyMongo (version 3.10)

All your files should end with a new line

The first line of all your files should be exactly #!/usr/bin/env python3

A README.md file, at the root of the folder of the project, is mandatory

Your code should use the pycodestyle style (version 2.5.*)

The length of your files will be tested using wc

All your modules should have a documentation ( python3 -c

'print(__import__("my_module").__doc__)' )

All your functions should have a documentation ( python3 -c

'print(__import__("my_module").my_function.__doc__)'

Your code should not be executed when imported (by using if __name__ ==

"__main__" :)

More Info

Install MongoDB 4.2 in Ubuntu 18.04


Official installation guide

$ wget -qO - https://www.mongodb.org/static/pgp/server-4.2.asc | apt-key add -


$ echo "deb [ arch=amd64,arm64 ] https://repo.mongodb.org/apt/ubuntu bionic/mongodb-or
g/4.2 multiverse" > /etc/apt/sources.list.d/mongodb-org-4.2.list
$ sudo apt-get update
$ sudo apt-get install -y mongodb-org
...
$ sudo service mongod status
mongod start/running, process 3627

Back-end - Storage 29
$ mongo --version
MongoDB shell version v4.2.8
git version: 43d25964249164d76d5e04dd6cf38f6111e21f5f
OpenSSL version: OpenSSL 1.1.1 11 Sep 2018
allocator: tcmalloc
modules: none
build environment:
distmod: ubuntu1804
distarch: x86_64
target_arch: x86_64
$
$ pip3 install pymongo
$ python3
>>> import pymongo
>>> pymongo.__version__
'3.10.1'

Potential issue if documents creation doesn’t work or this error: Data directory

/data/db not found., terminating (source and source)

$ sudo mkdir -p /data/db

Or if /etc/init.d/mongod is missing, please find here an example of the file:

Click to expand/hide file contents

#!/bin/sh
### BEGIN INIT INFO
# Provides: mongod
# Required-Start: $network $local_fs $remote_fs
# Required-Stop: $network $local_fs $remote_fs
# Should-Start: $named
# Should-Stop:
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: An object/document-oriented database
# Description: MongoDB is a high-performance, open source, schema-free
# document-oriented data store that's easy to deploy, manage
# and use. It's network accessible, written in C++ and offers
# the following features:
#
# * Collection oriented storage - easy storage of object-
# style data
# * Full index support, including on inner objects
# * Query profiling
# * Replication and fail-over support
# * Efficient storage of binary data including large
# objects (e.g. videos)
# * Automatic partitioning for cloud-level scalability
#
# High performance, scalability, and reasonable depth of
# functionality are the goals for the project.

Back-end - Storage 30
### END INIT INFO

PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin
DAEMON=/usr/bin/mongod
DESC=database

NAME=mongod
# Defaults. Can be overridden by the /etc/default/$NAME
# Other configuration options are located in $CONF file. See here for more:
# http://dochub.mongodb.org/core/configurationoptions
CONF=/etc/mongod.conf
PIDFILE=/var/run/$NAME.pid
ENABLE_MONGOD=yes

# Include mongodb defaults if available.


# All variables set before this point can be overridden by users, by
# setting them directly in the defaults file. Use this to explicitly
# override these values, at your own risk.
if [ -f /etc/default/$NAME ] ; then
. /etc/default/$NAME
fi

# Handle NUMA access to CPUs (SERVER-3574)


# This verifies the existence of numactl as well as testing that the command works
NUMACTL_ARGS="--interleave=all"
if which numactl >/dev/null 2>/dev/null && numactl $NUMACTL_ARGS ls / >/dev/null 2
>/dev/null
then
NUMACTL="`which numactl` -- $NUMACTL_ARGS"
DAEMON_OPTS=${DAEMON_OPTS:-"--config $CONF"}
else
NUMACTL=""
DAEMON_OPTS="-- "${DAEMON_OPTS:-"--config $CONF"}
fi

if test ! -x $DAEMON; then


echo "Could not find $DAEMON"
exit 0
fi

if test "x$ENABLE_MONGOD" != "xyes"; then


exit 0
fi

. /lib/lsb/init-functions

STARTTIME=1
DIETIME=10 # Time to wait for the server to die, in seconds
# If this value is set too low you might not
# let some servers to die gracefully and
# 'restart' will not work

DAEMONUSER=${DAEMONUSER:-mongodb}
DAEMONGROUP=${DAEMONGROUP:-mongodb}

set -e

Back-end - Storage 31
running_pid() {
# Check if a given process pid's cmdline matches a given name
pid=$1
name=$2
[ -z "$pid" ] && return 1
[ ! -d /proc/$pid ] && return 1
cmd=`cat /proc/$pid/cmdline | tr "\000" "\n"|head -n 1 |cut -d : -f 1`
# Is this the expected server
[ "$cmd" != "$name" ] && return 1
return 0
}

running() {
# Check if the process is running looking at /proc
# (works for all users)

# No pidfile, probably no daemon present


[ ! -f "$PIDFILE" ] && return 1
pid=`cat $PIDFILE`
running_pid $pid $DAEMON || return 1
return 0
}

start_server() {
# Start the process using the wrapper
start-stop-daemon --background --start --quiet --pidfile $PIDFILE \
--make-pidfile --chuid $DAEMONUSER:$DAEMONGROUP \
--exec $NUMACTL $DAEMON $DAEMON_OPTS
errcode=$?
return $errcode
}

stop_server() {
# Stop the process using the wrapper
start-stop-daemon --stop --quiet --pidfile $PIDFILE \
--retry 300 \
--user $DAEMONUSER \
--exec $DAEMON
errcode=$?
return $errcode
}

force_stop() {
# Force the process to die killing it manually
[ ! -e "$PIDFILE" ] && return
if running ; then
kill -15 $pid
# Is it really dead?
sleep "$DIETIME"s
if running ; then
kill -9 $pid
sleep "$DIETIME"s
if running ; then
echo "Cannot kill $NAME (pid=$pid)!"
exit 1
fi
fi
fi

Back-end - Storage 32
rm -f $PIDFILE
}

case "$1" in
start)
log_daemon_msg "Starting $DESC" "$NAME"
# Check if it's running first
if running ; then
log_progress_msg "apparently already running"
log_end_msg 0
exit 0
fi
if start_server ; then
# NOTE: Some servers might die some time after they start,
# this code will detect this issue if STARTTIME is set
# to a reasonable value
[ -n "$STARTTIME" ] && sleep $STARTTIME # Wait some time
if running ; then
# It's ok, the server started and is running
log_end_msg 0
else
# It is not running after we did start
log_end_msg 1
fi
else
# Either we could not start it
log_end_msg 1
fi
;;
stop)
log_daemon_msg "Stopping $DESC" "$NAME"
if running ; then
# Only stop the server if we see it running
errcode=0
stop_server || errcode=$?
log_end_msg $errcode
else
# If it's not running don't do anything
log_progress_msg "apparently not running"
log_end_msg 0
exit 0
fi
;;
force-stop)
# First try to stop gracefully the program
$0 stop
if running; then
# If it's still running try to kill it more forcefully
log_daemon_msg "Stopping (force) $DESC" "$NAME"
errcode=0
force_stop || errcode=$?
log_end_msg $errcode
fi
;;
restart|force-reload)
log_daemon_msg "Restarting $DESC" "$NAME"
errcode=0

Back-end - Storage 33
stop_server || errcode=$?
# Wait some sensible amount, some server need this
[ -n "$DIETIME" ] && sleep $DIETIME
start_server || errcode=$?
[ -n "$STARTTIME" ] && sleep $STARTTIME
running || errcode=$?
log_end_msg $errcode
;;
status)

log_daemon_msg "Checking status of $DESC" "$NAME"


if running ; then
log_progress_msg "running"
log_end_msg 0
else
log_progress_msg "apparently not running"
log_end_msg 1
exit 1
fi
;;
# MongoDB can't reload its configuration.
reload)
log_warning_msg "Reloading $NAME daemon: not implemented, as the daemon"
log_warning_msg "cannot re-read the config file (use restart)."
;;

*)
N=/etc/init.d/$NAME
echo "Usage: $N {start|stop|force-stop|restart|force-reload|status}" >&2
exit 1
;;
esac

exit 0

Use “container-on-demand” to run


MongoDB
Ask for container Ubuntu 18.04 - MongoDB

Connect via SSH

Or via the WebTerminal

In the container, you should start MongoDB before playing with it:

$ service mongod start


* Starting database mongod [ OK ]
$
$ cat 0-list_databases | mongo
MongoDB shell version v4.2.8

Back-end - Storage 34
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongo
db
Implicit session: session { "id" : UUID("70f14b38-6d0b-48e1-a9a4-0534bcf15301") }
MongoDB server version: 4.2.8
admin 0.000GB
config 0.000GB
local 0.000GB
bye
$

Tasks
0. List all databases
mandatory

Score: 88.33% (Checks completed: 100.0%)


Write a script that lists all databases in MongoDB.

guillaume@ubuntu:~/0x01$ cat 0-list_databases | mongo


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
admin 0.000GB
config 0.000GB
local 0.000GB
logs 0.005GB
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 0-list_databases

Done? Help Check your code Get a sandbox QA Review

1. Create a database
mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a script that creates or uses the database my_db :

Back-end - Storage 35
guillaume@ubuntu:~/0x01$ cat 0-list_databases | mongo
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
admin 0.000GB
config 0.000GB
local 0.000GB
logs 0.005GB
bye
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ cat 1-use_or_create_database | mongo
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017
MongoDB server version: 3.6.3
switched to db my_db
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 1-use_or_create_database

Done? Help Check your code Get a sandbox QA Review

2. Insert document
mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a script that inserts a document in the collection school :

The document must have one attribute name with value “Holberton school”

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 2-insert | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
WriteResult({ "nInserted" : 1 })
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Back-end - Storage 36
Directory: 0x01-NoSQL

File: 2-insert

Done? Help Check your code Get a sandbox QA Review

3. All documents
mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a script that lists all documents in the collection school :

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 3-all | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
{ "_id" : ObjectId("5a8fad532b69437b63252406"), "name" : "Holberton school" }
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 3-all

Done? Help Check your code Get a sandbox QA Review

4. All matches
mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a script that lists all documents with name="Holberton school" in the
collection school :

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 4-match | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
{ "_id" : ObjectId("5a8fad532b69437b63252406"), "name" : "Holberton school" }

Back-end - Storage 37
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 4-match

Done? Help Check your code Get a sandbox QA Review

5. Count
mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a script that displays the number of documents in the collection school :

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 5-count | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
1
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 5-count

Done? Help Check your code Get a sandbox QA Review

6. Update
mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a script that adds a new attribute to a document in the collection school :

The script should update only document with name="Holberton school" (all of them)

Back-end - Storage 38
The update should add the attribute address with the value “972 Mission street”

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 6-update | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
bye
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ cat 4-match | mongo my_db
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
{ "_id" : ObjectId("5a8fad532b69437b63252406"), "name" : "Holberton school", "address"
: "972 Mission street" }
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 6-update

Done? Help Check your code Get a sandbox QA Review

7. Delete by match
mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a script that deletes all documents with name="Holberton school" in the
collection school :

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 7-delete | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
{ "acknowledged" : true, "deletedCount" : 1 }
bye
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ cat 4-match | mongo my_db
MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db

Back-end - Storage 39
MongoDB server version: 3.6.3
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 7-delete

Done? Help Check your code Get a sandbox QA Review

8. List all documents in Python


mandatory

Score: 100.0% (Checks completed: 100.0%)


Write a Python function that lists all documents in a collection:

Prototype: def list_all(mongo_collection):

Return an empty list if no document in the collection

mongo_collection will be the pymongo collection object

guillaume@ubuntu:~/0x01$ cat 8-main.py


#!/usr/bin/env python3
""" 8-main """
from pymongo import MongoClient
list_all = __import__('8-all').list_all

if __name__ == "__main__":
client = MongoClient('mongodb://127.0.0.1:27017')
school_collection = client.my_db.school
schools = list_all(school_collection)
for school in schools:
print("[{}] {}".format(school.get('_id'), school.get('name')))

guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./8-main.py
[5a8f60cfd4321e1403ba7ab9] Holberton school
[5a8f60cfd4321e1403ba7aba] UCSD
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

Back-end - Storage 40
File: 8-all.py

Done? Help Check your code Get a sandbox QA Review

9. Insert a document in Python


mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a Python function that inserts a new document in a collection based on kwargs :

Prototype: def insert_school(mongo_collection, **kwargs):

mongo_collection will be the pymongo collection object

Returns the new _id

guillaume@ubuntu:~/0x01$ cat 9-main.py


#!/usr/bin/env python3
""" 9-main """
from pymongo import MongoClient
list_all = __import__('8-all').list_all
insert_school = __import__('9-insert_school').insert_school

if __name__ == "__main__":
client = MongoClient('mongodb://127.0.0.1:27017')
school_collection = client.my_db.school
new_school_id = insert_school(school_collection, name="UCSF", address="505 Parnass
us Ave")
print("New school created: {}".format(new_school_id))

schools = list_all(school_collection)
for school in schools:
print("[{}] {} {}".format(school.get('_id'), school.get('name'), school.get('a
ddress', "")))

guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./9-main.py
New school created: 5a8f60cfd4321e1403ba7abb
[5a8f60cfd4321e1403ba7ab9] Holberton school
[5a8f60cfd4321e1403ba7aba] UCSD
[5a8f60cfd4321e1403ba7abb] UCSF 505 Parnassus Ave
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 9-insert_school.py

Back-end - Storage 41
Done? Help Check your code Get a sandbox QA Review

10. Change school topics


mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a Python function that changes all topics of a school document based on the
name:

Prototype: def update_topics(mongo_collection, name, topics):

mongo_collection will be the pymongo collection object

name (string) will be the school name to update

topics (list of strings) will be the list of topics approached in the school

guillaume@ubuntu:~/0x01$ cat 10-main.py


#!/usr/bin/env python3
""" 10-main """
from pymongo import MongoClient
list_all = __import__('8-all').list_all
update_topics = __import__('10-update_topics').update_topics

if __name__ == "__main__":
client = MongoClient('mongodb://127.0.0.1:27017')
school_collection = client.my_db.school
update_topics(school_collection, "Holberton school", ["Sys admin", "AI", "Algorith
m"])

schools = list_all(school_collection)
for school in schools:
print("[{}] {} {}".format(school.get('_id'), school.get('name'), school.get('t
opics', "")))

update_topics(school_collection, "Holberton school", ["iOS"])

schools = list_all(school_collection)
for school in schools:
print("[{}] {} {}".format(school.get('_id'), school.get('name'), school.get('t
opics', "")))

guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./10-main.py
[5a8f60cfd4321e1403ba7abb] UCSF
[5a8f60cfd4321e1403ba7aba] UCSD
[5a8f60cfd4321e1403ba7ab9] Holberton school ['Sys admin', 'AI', 'Algorithm']
[5a8f60cfd4321e1403ba7abb] UCSF
[5a8f60cfd4321e1403ba7aba] UCSD
[5a8f60cfd4321e1403ba7ab9] Holberton school ['iOS']
guillaume@ubuntu:~/0x01$

Back-end - Storage 42
Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 10-update_topics.py

Done? Help Check your code Get a sandbox QA Review

11. Where can I learn Python?


mandatory
Score: 100.0% (Checks completed: 100.0%)

Write a Python function that returns the list of school having a specific topic:

Prototype: def schools_by_topic(mongo_collection, topic):

mongo_collection will be the pymongo collection object

topic (string) will be topic searched

guillaume@ubuntu:~/0x01$ cat 11-main.py


#!/usr/bin/env python3
""" 11-main """
from pymongo import MongoClient
list_all = __import__('8-all').list_all
insert_school = __import__('9-insert_school').insert_school
schools_by_topic = __import__('11-schools_by_topic').schools_by_topic

if __name__ == "__main__":
client = MongoClient('mongodb://127.0.0.1:27017')
school_collection = client.my_db.school

j_schools = [
{ 'name': "Holberton school", 'topics': ["Algo", "C", "Python", "React"]},
{ 'name': "UCSF", 'topics': ["Algo", "MongoDB"]},
{ 'name': "UCLA", 'topics': ["C", "Python"]},
{ 'name': "UCSD", 'topics': ["Cassandra"]},
{ 'name': "Stanford", 'topics': ["C", "React", "Javascript"]}
]
for j_school in j_schools:
insert_school(school_collection, **j_school)

schools = schools_by_topic(school_collection, "Python")


for school in schools:
print("[{}] {} {}".format(school.get('_id'), school.get('name'), school.get('t
opics', "")))

guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./11-main.py
[5a90731fd4321e1e5a3f53e3] Holberton school ['Algo', 'C', 'Python', 'React']

Back-end - Storage 43
[5a90731fd4321e1e5a3f53e5] UCLA ['C', 'Python']
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 11-schools_by_topic.py

Done? Help Check your code Get a sandbox QA Review

12. Log stats


mandatory

Score: 100.0% (Checks completed: 100.0%)

Write a Python script that provides some stats about Nginx logs stored in MongoDB:

Database: logs

Collection: nginx

Display (same as the example):

first line: x logs where x is the number of documents in this collection

second line: Methods:

5 lines with the number of documents with the method = ["GET", "POST",
"PUT", "PATCH", "DELETE"] in this order (see example below - warning: it’s a

tabulation before each line)

one line with the number of documents with:

method=GET

path=/status

You can use this dump as data sample: dump.zip

The output of your script must be exactly the same as the example

guillaume@ubuntu:~/0x01$ curl -o dump.zip -s "https://s3.amazonaws.com/intranet-projec


ts-files/holbertonschool-webstack/411/dump.zip"
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ unzip dump.zip
Archive: dump.zip
creating: dump/
creating: dump/logs/

Back-end - Storage 44
inflating: dump/logs/nginx.metadata.json
inflating: dump/logs/nginx.bson
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ mongorestore dump
2018-02-23T20:12:37.807+0000 preparing collections to restore from
2018-02-23T20:12:37.816+0000 reading metadata for logs.nginx from dump/logs/nginx.m
etadata.json
2018-02-23T20:12:37.825+0000 restoring logs.nginx from dump/logs/nginx.bson
2018-02-23T20:12:40.804+0000 [##......................] logs.nginx 1.21MB/13.4MB
(9.0%)
2018-02-23T20:12:43.803+0000 [#####...................] logs.nginx 2.88MB/13.4MB
(21.4%)
2018-02-23T20:12:46.803+0000 [#######.................] logs.nginx 4.22MB/13.4MB
(31.4%)
2018-02-23T20:12:49.803+0000 [##########..............] logs.nginx 5.73MB/13.4MB
(42.7%)
2018-02-23T20:12:52.803+0000 [############............] logs.nginx 7.23MB/13.4MB
(53.8%)
2018-02-23T20:12:55.803+0000 [###############.........] logs.nginx 8.53MB/13.4MB
(63.5%)
2018-02-23T20:12:58.803+0000 [#################.......] logs.nginx 10.1MB/13.4MB
(74.9%)
2018-02-23T20:13:01.803+0000 [####################....] logs.nginx 11.3MB/13.4MB
(83.9%)
2018-02-23T20:13:04.803+0000 [######################..] logs.nginx 12.8MB/13.4MB
(94.9%)
2018-02-23T20:13:06.228+0000 [########################] logs.nginx 13.4MB/13.4MB
(100.0%)
2018-02-23T20:13:06.230+0000 no indexes to restore
2018-02-23T20:13:06.231+0000 finished restoring logs.nginx (94778 documents)
2018-02-23T20:13:06.232+0000 done
guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./12-log_stats.py
94778 logs
Methods:
method GET: 93842
method POST: 229
method PUT: 0
method PATCH: 0
method DELETE: 0
47415 status check
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 12-log_stats.py

Done? Help Check your code Get a sandbox QA Review

13. Regex filter

Back-end - Storage 45
#advanced

Score: 100.0% (Checks completed: 100.0%)

Write a script that lists all documents with name starting by Holberton in the
collection school :

The database name will be passed as option of mongo command

guillaume@ubuntu:~/0x01$ cat 100-find | mongo my_db


MongoDB shell version v3.6.3
connecting to: mongodb://127.0.0.1:27017/my_db
MongoDB server version: 3.6.3
{ "_id" : ObjectId("5a90731fd4321e1e5a3f53e3"), "name" : "Holberton school" }
{ "_id" : ObjectId("5a90731fd4321e1e5a3f53e3"), "name" : "Holberton School" }
{ "_id" : ObjectId("5a90731fd4321e1e5a3f53e3"), "name" : "Holberton-school" }
bye
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 100-find

Done? Help Check your code Get a sandbox QA Review

14. Top students


#advanced

Score: 100.0% (Checks completed: 100.0%)

Write a Python function that returns all students sorted by average score:

Prototype: def top_students(mongo_collection):

mongo_collection will be the pymongo collection object

The top must be ordered

The average score must be part of each item returns with key = averageScore

guillaume@ubuntu:~/0x01$ cat 101-main.py


#!/usr/bin/env python3
""" 101-main """
from pymongo import MongoClient
list_all = __import__('8-all').list_all
insert_school = __import__('9-insert_school').insert_school

Back-end - Storage 46
top_students = __import__('101-students').top_students

if __name__ == "__main__":
client = MongoClient('mongodb://127.0.0.1:27017')
students_collection = client.my_db.students

j_students = [
{ 'name': "John", 'topics': [{ 'title': "Algo", 'score': 10.3 },{ 'title':
"C", 'score': 6.2 }, { 'title': "Python", 'score': 12.1 }]},
{ 'name': "Bob", 'topics': [{ 'title': "Algo", 'score': 5.4 },{ 'title': "C",
'score': 4.9 }, { 'title': "Python", 'score': 7.9 }]},
{ 'name': "Sonia", 'topics': [{ 'title': "Algo", 'score': 14.8 },{ 'title':
"C", 'score': 8.8 }, { 'title': "Python", 'score': 15.7 }]},
{ 'name': "Amy", 'topics': [{ 'title': "Algo", 'score': 9.1 },{ 'title': "C",
'score': 14.2 }, { 'title': "Python", 'score': 4.8 }]},
{ 'name': "Julia", 'topics': [{ 'title': "Algo", 'score': 10.5 },{ 'title':
"C", 'score': 10.2 }, { 'title': "Python", 'score': 10.1 }]}
]
for j_student in j_students:
insert_school(students_collection, **j_student)

students = list_all(students_collection)
for student in students:
print("[{}] {} - {}".format(student.get('_id'), student.get('name'), student.g
et('topics')))

top_students = top_students(students_collection)
for student in top_students:
print("[{}] {} => {}".format(student.get('_id'), student.get('name'), student.
get('averageScore')))

guillaume@ubuntu:~/0x01$
guillaume@ubuntu:~/0x01$ ./101-main.py
[5a90776bd4321e1ec94fc408] John - [{'title': 'Algo', 'score': 10.3}, {'title': 'C', 's
core': 6.2}, {'title': 'Python', 'score': 12.1}]
[5a90776bd4321e1ec94fc409] Bob - [{'title': 'Algo', 'score': 5.4}, {'title': 'C', 'sco
re': 4.9}, {'title': 'Python', 'score': 7.9}]
[5a90776bd4321e1ec94fc40a] Sonia - [{'title': 'Algo', 'score': 14.8}, {'title': 'C',
'score': 8.8}, {'title': 'Python', 'score': 15.7}]
[5a90776bd4321e1ec94fc40b] Amy - [{'title': 'Algo', 'score': 9.1}, {'title': 'C', 'sco
re': 14.2}, {'title': 'Python', 'score': 4.8}]
[5a90776bd4321e1ec94fc40c] Julia - [{'title': 'Algo', 'score': 10.5}, {'title': 'C',
'score': 10.2}, {'title': 'Python', 'score': 10.1}]
[5a90776bd4321e1ec94fc40a] Sonia => 13.1
[5a90776bd4321e1ec94fc40c] Julia => 10.266666666666666
[5a90776bd4321e1ec94fc408] John => 9.533333333333333
[5a90776bd4321e1ec94fc40b] Amy => 9.366666666666665
[5a90776bd4321e1ec94fc409] Bob => 6.066666666666667
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

Back-end - Storage 47
File: 101-students.py

Done? Help Check your code Get a sandbox QA Review

15. Log stats - new version


#advanced

Score: 100.0% (Checks completed: 100.0%)


Improve 12-log_stats.py by adding the top 10 of the most present IPs in the
collection nginx of the database logs :

The IPs top must be sorted (like the example below)

guillaume@ubuntu:~/0x01$ ./102-log_stats.py
94778 logs
Methods:
method GET: 93842
method POST: 229
method PUT: 0
method PATCH: 0
method DELETE: 0
47415 status check
IPs:
172.31.63.67: 15805
172.31.2.14: 15805
172.31.29.194: 15805
69.162.124.230: 529
64.124.26.109: 408
64.62.224.29: 217
34.207.121.61: 183
47.88.100.4: 166
45.249.84.250: 160
216.244.66.228: 150
guillaume@ubuntu:~/0x01$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x01-NoSQL

File: 102-log_stats.py

0x02. Redis basic


Back-endRedis

Back-end - Storage 48
By: Emmanuel Turlay, Staff Software Engineer at Cruise

Weight: 1

Project over - took place from Feb 15, 2023 5:00 AM to Feb 16, 2023 5:00 AM

An auto review will be launched at the deadline

In a nutshell…
Auto QA review: 27.0/27 mandatory & 4.0/6 optional

Altogether: 166.67%

Mandatory: 100.0%

Optional: 66.67%

Calculation: 100.0% + (100.0% * 66.67%) == 166.67%

Resources
Read or watch:

Back-end - Storage 49
Redis commands

Redis python client

How to Use Redis With Python

Redis Crash Course Tutorial

Learning Objectives
Learn how to use redis for basic operations

Learn how to use redis as a simple cache

Requirements
All of your files will be interpreted/compiled on Ubuntu 18.04 LTS using python3
(version 3.7)

All of your files should end with a new line

A README.md file, at the root of the folder of the project, is mandatory

The first line of all your files should be exactly #!/usr/bin/env python3

Your code should use the pycodestyle style (version 2.5)

All your modules should have documentation ( python3 -c

'print(__import__("my_module").__doc__)' )

All your classes should have documentation ( python3 -c

'print(__import__("my_module").MyClass.__doc__)' )

All your functions and methods should have documentation ( python3 -c

'print(__import__("my_module").my_function.__doc__)' and python3 -c

'print(__import__("my_module").MyClass.my_function.__doc__)' )

A documentation is not a simple word, it’s a real sentence explaining what’s the
purpose of the module, class or method (the length of it will be verified)

All your functions and coroutines must be type-annotated.

Install Redis on Ubuntu 18.04

Back-end - Storage 50
$ sudo apt-get -y install redis-server
$ pip3 install redis
$ sed -i "s/bind .*/bind 127.0.0.1/g" /etc/redis/redis.conf

Use Redis in a container


Redis server is stopped by default - when you are starting a container, you should
start it with: service redis-server start

Tasks
0. Writing strings to Redis
mandatory

Score: 100.0% (Checks completed: 100.0%)

Create a Cache class. In the __init__ method, store an instance of the Redis client
as a private variable named _redis (using redis.Redis() ) and flush the instance
using flushdb .

Create a store method that takes a data argument and returns a string. The
method should generate a random key (e.g. using uuid ), store the input data in
Redis using the random key and return the key.

Type-annotate store correctly. Remember that data can be


a str , bytes , int or float .

bob@dylan:~$ cat main.py


#!/usr/bin/env python3
"""
Main file
"""
import redis

Cache = __import__('exercise').Cache

cache = Cache()

data = b"hello"
key = cache.store(data)
print(key)

local_redis = redis.Redis()
print(local_redis.get(key))

Back-end - Storage 51
bob@dylan:~$ python3 main.py
3a3e8231-b2f6-450d-8b0e-0f38f16e8ca2
b'hello'
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: exercise.py

Done? Help Check your code Get a sandbox QA Review

1. Reading from Redis and recovering original type


mandatory

Score: 100.0% (Checks completed: 100.0%)

Redis only allows to store string, bytes and numbers (and lists thereof). Whatever
you store as single elements, it will be returned as a byte string. Hence if you
store "a" as a UTF-8 string, it will be returned as b"a" when retrieved from the
server.

In this exercise we will create a get method that take a key string argument and an
optional Callable argument named fn . This callable will be used to convert the data
back to the desired format.

Remember to conserve the original Redis.get behavior if the key does not exist.

Also, implement 2 new methods: get_str and get_int that will automatically
parametrize Cache.get with the correct conversion function.

The following code should not raise:

cache = Cache()

TEST_CASES = {
b"foo": None,
123: int,
"bar": lambda d: d.decode("utf-8")
}

for value, fn in TEST_CASES.items():


key = cache.store(value)
assert cache.get(key, fn=fn) == value

Back-end - Storage 52
Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: exercise.py

Done? Help Check your code Get a sandbox QA Review

2. Incrementing values
mandatory

Score: 100.0% (Checks completed: 100.0%)

Familiarize yourself with the INCR command and its python equivalent.

In this task, we will implement a system to count how many times methods of
the Cache class are called.
Above Cache define a count_calls decorator that takes a
single method Callable argument and returns a Callable .
As a key, use the qualified name of method using the __qualname__ dunder method.

Create and return function that increments the count for that key every time the
method is called and returns the value returned by the original method.

Remember that the first argument of the wrapped function will be self which is the
instance itself, which lets you access the Redis instance.

Protip: when defining a decorator it is useful to use functool.wraps to conserve the


original function’s name, docstring, etc. Make sure you use it as described here.

Decorate Cache.store with count_calls .

bob@dylan:~$ cat main.py


#!/usr/bin/env python3
""" Main file """

Cache = __import__('exercise').Cache

cache = Cache()

cache.store(b"first")
print(cache.get(cache.store.__qualname__))

cache.store(b"second")
cache.store(b"third")
print(cache.get(cache.store.__qualname__))

Back-end - Storage 53
bob@dylan:~$ ./main.py
b'1'
b'3'
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: exercise.py

Done? Help Check your code Get a sandbox QA Review

3. Storing lists
mandatory

Score: 100.0% (Checks completed: 100.0%)


Familiarize yourself with redis commands RPUSH , LPUSH , LRANGE , etc.

In this task, we will define a call_history decorator to store the history of inputs and
outputs for a particular function.

Everytime the original function will be called, we will add its input parameters to one
list in redis, and store its output into another list.

In call_history , use the decorated function’s qualified name and


append ":inputs" and ":outputs" to create input and output list keys, respectively.

call_history has a single parameter named method that is a Callable and returns
a Callable .

In the new function that the decorator will return, use rpush to append the input
arguments. Remember that Redis can only store strings, bytes and numbers.
Therefore, we can simply use str(args) to normalize. We can ignore
potential kwargs for now.

Execute the wrapped function to retrieve the output. Store the output using rpush in
the "...:outputs" list, then return the output.

Decorate Cache.store with call_history .

bob@dylan:~$ cat main.py


#!/usr/bin/env python3
""" Main file """

Cache = __import__('exercise').Cache

Back-end - Storage 54
cache = Cache()

s1 = cache.store("first")
print(s1)
s2 = cache.store("secont")
print(s2)
s3 = cache.store("third")
print(s3)

inputs = cache._redis.lrange("{}:inputs".format(cache.store.__qualname__), 0, -1)


outputs = cache._redis.lrange("{}:outputs".format(cache.store.__qualname__), 0, -1)

print("inputs: {}".format(inputs))
print("outputs: {}".format(outputs))

bob@dylan:~$ ./main.py
04f8dcaa-d354-4221-87f3-4923393a25ad
a160a8a8-06dc-4934-8e95-df0cb839644b
15a8fd87-1f55-4059-86aa-9d1a0d4f2aea
inputs: [b"('first',)", b"('secont',)", b"('third',)"]
outputs: [b'04f8dcaa-d354-4221-87f3-4923393a25ad', b'a160a8a8-06dc-4934-8e95-df0cb8396
44b', b'15a8fd87-1f55-4059-86aa-9d1a0d4f2aea']
bob@dylan:~$

Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: exercise.py

Done? Help Check your code Get a sandbox QA Review

4. Retrieving lists
mandatory

Score: 100.0% (Checks completed: 100.0%)

In this tasks, we will implement a replay function to display the history of calls of a
particular function.

Use keys generated in previous tasks to generate the following output:

>>> cache = Cache()


>>> cache.store("foo")
>>> cache.store("bar")
>>> cache.store(42)
>>> replay(cache.store)
Cache.store was called 3 times:
Cache.store(*('foo',)) -> 13bf32a9-a249-4664-95fc-b1062db2038f

Back-end - Storage 55
Cache.store(*('bar',)) -> dcddd00c-4219-4dd7-8877-66afbe8e7df8
Cache.store(*(42,)) -> 5e752f2b-ecd8-4925-a3ce-e2efdee08d20

Tip: use lrange and zip to loop over inputs and outputs.
Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: exercise.py

Done? Help Check your code Get a sandbox QA Review

5. Implementing an expiring web cache and tracker


#advanced

Score: 66.67% (Checks completed: 66.67%)

In this tasks, we will implement a get_page function (prototype: def get_page(url: str)

-> str: ). The core of the function is very simple. It uses the requests module to

obtain the HTML content of a particular URL and returns it.

Start in a new file named web.py and do not reuse the code written in exercise.py .

Inside get_page track how many times a particular URL was accessed in the
key "count:{url}" and cache the result with an expiration time of 10 seconds.

Tip: Use http://slowwly.robertomurray.co.uk to simulate a slow response and test your


caching.

Bonus: implement this use case with decorators.

Repo:

GitHub repository: alx-backend-storage

Directory: 0x02-redis_basic

File: web.py

Back-end - Storage 56

You might also like