| Version 10 (modified by , 7 days ago) ( diff ) |
|---|
Nutritioneer | Нормализација и оптимизација на дизајн
Денормализирана форма
Рамна табела од сите ентитети на Nutritioneer и нивните врски, без структурни ограничувања. Повеќевредносните факти се присутни како групи што се повторуваат: еден рецепт има многу состојки, многу диететски ограничувања и многу коментари, а една состојка носи многу нутриенти.
Функционални зависности
- user_id → email, username, password, role
- email → user_id (алтернативен клуч, UNIQUE)
- username → user_id (алтернативен клуч, UNIQUE)
- ingredient_id → ingredient_name, ingr_description, energy, kcal, ingr_type
- ingredient_name → ingredient_id (алтернативен клуч, UNIQUE)
- nutrient_id → nutr_description, rdi_quantity, unit, nutr_type
- nutr_description → nutrient_id (алтернативен клуч, UNIQUE)
- restriction_id → restr_description, restr_type
- restr_description → restriction_id (алтернативен клуч, UNIQUE)
- recipe_id → recipe_name, guide, kcal_sum, servings, user_id
- post_id → media, media_type, media_name, is_private, is_favourite, status, post_created_at, user_id, recipe_id
- recipe_id → post_id (POSTS_ON е 1:1, UNIQUE врз recipe_id)
- comment_id → comment_text, comment_created_at, post_id, user_id
- list_id → list_date_time, list_notes, is_bought, list_kcal, user_id
- planner_id → planner_date_time, planner_notes, planner_kcal, is_consumed, user_id
- bio_id → bio_date, weight, height, age, muscle_fat_ratio, user_id
- {user_id, bio_date} → bio_id (едно мерење по корисник на ден)
- {recipe_id, ingredient_id} → ingredient_quantity
- {ingredient_id, nutrient_id} → nutrient_amount
- {list_id, ingredient_id} → buy_quantity
Чисти M:N врски
Врските како recipe - restriction и grocery_list - grocery_list_bulk_add_ingredient неможат да определат дополнителен атрибут. Не се функционални зависности.
Почетна денормализирана релација
R( user_id, email, username, password, role, ingredient_id, ingredient_name, ingr_description, energy, kcal, ingr_type, nutrient_id, nutr_description, rdi_quantity, unit, nutr_type, restriction_id, restr_description, restr_type, recipe_id, recipe_name, guide, kcal_sum, servings, post_id, media, media_type, media_name, is_private, is_favourite, status, post_created_at, comment_id, comment_text, comment_created_at, list_id, list_date_time, list_notes, is_bought, list_kcal, planner_id, planner_date_time, planner_notes, planner_kcal, is_consumed, bio_id, bio_date, weight, height, age, muscle_fat_ratio, ingredient_quantity, nutrient_amount, buy_quantity )
Кандидат-клуч
1.X+ = R 2.X е минимално
Кандидати клучеви се следните:
K = { comment_id, ingredient_id, nutrient_id, restriction_id, list_id, planner_id, bio_id }
Атрибут што не се појавува на десната страна на ниедна функционална зависност никогаш не може да биде изведен, па мора да припаѓа на секој клуч. Пресметка на затворањето на K:
- comment_id → post_id, user_id; post_id → recipe_id; recipe_id → атрибути на рецептот; user_id → атрибути на корисникот
- ingredient_id → атрибути на состојката; {recipe_id, ingredient_id} → ingredient_quantity
- nutrient_id → атрибути на нутриентот; {ingredient_id, nutrient_id} → nutrient_amount
- restriction_id, list_id, planner_id, bio_id → нивните гранки; {list_id, ingredient_id} → buy_quantity
Проверка на минималност
- Отстранување на comment_id -> Се губи крајот на синџирот коментар → објава → рецепт → корисник.
- Отстранување на ingredient_id -> Се губи каталогот на храна, а со него и сите три атрибути за количина на врските.
- Oтстранување на nutrient_id -> Се губи гранката на нутриенти и nutrient_amount.
- Oтстранување на restriction_id -> Се губи гранката на диететски ознаки
- Oтстранување на list_id, planner_id или bio_id -> Се губат соодветните ентитети. Ниедна од нив не е определена од ништо друго.
Примерок од денормализирани податоци
Истиот корисник, рецепт, состојка и количина на нутриент се повторуваат по еднаш за секој коментар и по еднаш за секое ограничување. Промена на име на рецепт би барала ажурирање на секој од овие редови — аномалија при промена — а бришењето на последниот коментар би го избришало и фактот дека рецептот содржи бел грав — аномалија при бришење.
| username | recipe name | ingredient name | nutrient descr | nutrient amount | restriction type | comment |
|---|---|---|---|---|---|---|
| marija_t | Tavce Gravce | Dry White Beans | Protein | 21.0 | vegan | How long should I let it simmer and soak? |
| marija_t | Tavce Gravce | Dry White Beans | Protein | 21.0 | vegan | How long should you keep stirring the pot? |
| marija_t | Tavce Gravce | Dry White Beans | Protein | 21.0 | gluten_free | What is in the sauce? |
ПРВА(1NF)
Релацијата е во 1NF кога: • Редоследот на редовите нема значење • Секој атрибут содржи атомски вредности • Типовите на податоци се доследни • Примарен клуч еднозначно го идентификува секој запис • Не постојат групи што се повторуваат
Постапката за подготовка на рецептот се чува како една текстуална вредност наместо како листа чекори, бидејќи чекорите никогаш не се пребаруваат поединечно. Релацијата ја задоволува 1NF така што секој атрибут содржи една атомска вредност идентификувано со K.
ВТОРА(2NF)
За да се постигне 2NF: • 1NF + • Парцијалните зависности мора да се отстранат. • Атрибутите што зависат само од дел од K мора да се издвојат во независни релации.
- R -> Целосна шема
- R′ -> Шема после издвојување
Секој атрибут на R зависи само од една компонента на K (или од пар извлечен од неа), никогаш од целиот K, па секоја гранка е парцијална зависност и се издвојува во сопствена релација.
Декомпозиција во 2NF
R1 - USER
Проверка на кандидат-клучот: user_id е примарен клуч. email и username се алтернативни (unique) K. Не постојат парцијални зависности.
{user_id} → {email, username, password, role}
| user_id | username | password | role | |
|---|---|---|---|---|
| 6 | acko@… | acko_l | testPass@1 | admin |
| 8 | marija.trajko@… | marija_t | testPass@1 | user |
- Спојување без загуба во случајов се изведува од R1 ∩ R′ = {user_id}
R2 - INGREDIENT
Проверка на кандидат-клучот: ingredient_id е примарен клуч; ingredient_name е алтернативен К.
{ingredient_id} → {ingredient_name, ingr_description, energy, kcal, ingr_type}
| ingredient_id | name | description | energy | kcal | type |
|---|---|---|---|---|---|
| 26 | Onion | White or Red, will make you cry | 167 | 40 | vegetable |
| 28 | Bread | Plain Bread | 1000 | 40 | carbs |
- Спојување без загуба во случајов се изведува од R1 ∩ R′ = {ingredient_id}
R3 - NUTRIENT
Проверка на кандидат-клучот: nutrient_id е примарен клуч; nutr_description е алтернативен K.
{nutrient_id} → {nutr_description, rdi_quantity, unit, nutr_type}
| nutrient_id | description | quantity | unit | type |
|---|---|---|---|---|
| 1 | Protein | 50 | gram | macro |
| 9 | Vitamin C | 80 | milligram | micro |
- Спојување без загуба во случајов се изведува од R3 ∩ R′ = {nutrient_id}
R4 - RESTRICTION
Проверка на кандидат-клучот: restriction_id е примарен клуч; restr_description е алтернативен K.
{restriction_id} → {restr_description, restr_type}
| restriction_id | restr_description | type |
|---|---|---|
| 12 | No animal origins | vegan |
| 20 | Only animal origins | carnivore |
- Спојување без загуба во случајов се изведува од R4 ∩ R′ = {restriction_id}
R5 - RECIPE
Проверка на кандидат-клучот: recipe_id е примарен клуч. user_id е надворешен клуч кон R1.
{recipe_id} → {recipe_name, guide, kcal_sum, servings, user_id}
| recipe_id | name | guide | kcal_sum | servings | user_id |
|---|---|---|---|---|---|
| 1 | Omlette | 1.Get Eggs 2... | 1167 | 1 | 2 |
| 2 | Cesar Salad | 1. Get Bowl 2... | 2400 | 2 | 3 |
- Спојување без загуба во случајов се изведува од R5 ∩ R′ = {recipe_id, user_id}
R6 - POST
Проверка на кандидат-клучот: post_id е примарен клуч. recipe_id е алтернативен клуч (UNIQUE, дозволува NULL), кој ја реализира врската POSTS_ON 1:1. user_id ја реализира CREATES.
{post_id} → {media, media_type, media_name, is_private, is_favourite, status, post_created_at, user_id, recipe_id}
| post_id | is_private | is_favourite | status | created_at | user_id | recipe_id |
|---|---|---|---|---|---|---|
| 1 | true | true | published | 2026-01-30 07:30 | 2 | NULL |
| 2 | true | false | published | 2026-03-20 09:35 | 3 | 1 |
- Спојување без загуба во случајов се изведува од R6 ∩ R′ = {post_id, user_id, recipe_id}.
R7 - COMMENT
Проверка на кандидат-клучот: comment_id е примарен клуч.
{comment_id} → {comment_text, comment_created_at, post_id, user_id}
| comment_id | description | created_at | post_id | user_id |
|---|---|---|---|---|
| 12 | Pozdrav do Baba Rada | 2026-01-30 07:30 | 3 | 1 |
| 29 | Vkusno i zdravo | 2026-12-10 08:30 | 2 | 5 |
- Спојување без загуба во случајов се изведува од R7 ∩ R′ = {comment_id, post_id, user_id}.
R8 - GROCERY_LIST
Проверка на кандидат-клучот: list_id е примарен клуч.
{list_id} → {list_date_time, list_notes, is_bought, list_kcal, user_id}
| list_id | date_time | notes | is_bought | kcal | user_id |
|---|---|---|---|---|---|
| 12 | 2026-01-30 07:30 | Sabota Rucek | true | 1167 | 2 |
| 23 | 2026-12-10 08:30 | Igor Rodenden | true | 2400 | 3 |
- Спојување без загуба во случајов се изведува од R8 ∩ R′ = {list_id, user_id}.
R9 - INTAKE_PLANNER
Проверка на кандидат-клучот: planner_id е примарен клуч.
{planner_id} → {planner_date_time, planner_notes, planner_kcal, is_consumed, user_id}
| planner_id | date_time | notes | kcal | is_consumed | user_id |
|---|---|---|---|---|---|
| 12 | 2026-01-30 07:30 | Sabota Rucek | 1167 | true | 2 |
| 23 | 2026-12-10 08:30 | Igor Rodenden | 2400 | true | 3 |
- Спојување без загуба во случајов се изведува од R9 ∩ R′ = {planner_id, user_id}.
R10 - BIOMETRICS
R11 - RECIPE_CONTAINS_INGREDIENT
R12 - INGREDIENT_CONTAINS_NUTRIENT
R13 - RECIPE_CONTAINS_RESTRICTION
R14 - GROCERY_LIST_BULK_ADD_INGREDIENT
R15 - GROCERY_LIST_SINGLE_ADD_INGREDIENT
R16 - INTAKE_PLANNER_SAVE_TO_LIST_POST
ТРЕТА(3NF)
БОЈС-КОДОВА (BCNF)
Навигација низ проектот
| Фаза | Име на фаза | Статус |
|---|---|---|
| P0 | Дефинирање проект | Одобрен |
| P1 | Концептуален дизајн и ЕР Дијаграм | Одобрен |
| P2 | Логички и физички дизајн - DDL | Одобрен |
| P3 | Кориснички/апикациски сценарија со базата на податоци | Одобрен |
| P4 | Протип со основни функционалности | WIP |
| М1 | Презентација на прототип | WIP |
| P5 | Нормализација и оптимизација на дизајн | WIP |
| P6 | Напредни извештаи од базата | WIP |
| P7 | Понапреден развој на базата | WIP |
| P8 | Напреден апликативен развој | WIP |
| P9 | Дополнителни имплементации | WIP |
| М2 | Финализиран проект | WIP |
(Trac навигација)
- TracGuide Documentation
