Модель данных - moevm/nosql2h24-dogs GitHub Wiki
Модель данных
Нереляционная модель
- Графическое представление модели Модель состоит из трёх коллекций:
BREED:
Так как с ростом количества комментариев коллекция может превысить максимальный размер коллекции mongodb (16мб), коллекция BREED может быть использована совместно со спецификацией GridFS.
USER:
EVENT:
- Описание назначений коллекций, типов данных и сущностей
Breed хранит информацию о различных породах собак, включая их характеристики, изображения, комментарии от пользователей и лайки на комментарии. Содержимое:
_id: string - Уникальный идентификатор породы.
name: string - Название породы.
image: string - URL изображения породы.
parameters*: array - Массив с параметрами породы.
comments: array - Массив комментариев, где каждый комментарий является объектом, содержащим:
id: string - Уникальный идентификатор комментария.
author: string - Id автора комментария.
parent_comments_id: string|null - Идентификатор родительского комментария (null, если комментарий родительский в своей ветке).
date: ISODate - Дата и время написания комментария.
text: string - Текст комментария.
likes: array - Массив id пользователей, которые поставили лайк конкретному комментарию.
*Элементы массива parameters:
weight_imperial: string
weight_metric: string
vetstreet_url: string
temperament: string
origin: string
country_codes: string
country_code: string
description: string
life_span: string
indoor: integer
alt_names: string
adaptability: integer
affection_level: integer
child_friendly: integer
dog_friendly: integer
energy_level: integer
grooming: integer
health_issues: integer
intelligence: integer
shedding_level: integer
social_needs: integer
stranger_friendly: integer
vocalisation: integer
experimental: integer
hairless: integer
natural: integer
rare: integer
rex: integer
suppressed_tail: integer
short_legs: integer
wikipedia_url: string
hypoallergenic: integer
User xранит информацию о пользователях системы, включая имя, возраст, времяя создания и последнего редактирования профиля, наличие статуса администратора и избранные породы.
Содержимое:
_id: string - Уникальный идентификатор пользователя.
name: string - Имя пользователя.
age: integer - Возраст пользователя.
isAdmin: boolean - Наличие у пользователя статуса администратора.
passwordHash: string - Хеш пароля пользователя.
image: string|null - URL изображение пользователя (null, если изображения нет).
creation_date: ISODate - Дата и время создания учетной записи пользователя.
last_date: ISODate - Дата и время последнего входа пользователя.
favorites: array - Массив id пород, добавленных пользователем в избранное.
Event xранит сведения о действиях пользователей, связанных с породами собак.
Содержимое:
_id: string - Уникальный идентификатор действия.
user_id: string - Id пользователя, совершившего действие.
breed_id: string - Id породы, с которой связано событие.
type: string - Тип произошедшего события.
date: ISODate - Дата и время возникновения события.
- Оценка объема информации, хранимой в модели Один лайк занимает 36 байт (один Id пользователя) Один комментарий занимает 540 байтов + 36 х кол-во лайков Одна запись в коллекции Breed в среднем занимает 806 байтов + (540 байтов + 36 х среднее кол-во лайков) х среднее кол-во комментариев
Одна запись о любимой породе занимает 36 байтов (один Id породы) Предположим, что у одного пользователя в среднем 5 любимых пород. Тогда: Одна запись в коллекции User в среднем занимает 337 байтов
Одна запись в коллекции Event занимает 136 байтов.
В качестве переменной возьмём количество пользователей. Количество пород возьмём равное 200. Пусть пользователь в среднем оставляет 20 комментариев, ставит 100 лайков, имеет 100 любимых пород и генерирует 1000 событий. Тогда объём модели занимает: 200 х 806 + n х 540 + n х 36 + n х 337 + n х 100 х 36 + 1000 х 136 х n = 161200 + 140513 х n байтов
-
Избыточность данных
В модели используются избыточные данные об ссылающихся друг на друга id (события, комментарии и лайки ссылаются на пользователей, события ссылаются на породы и тп). Избыточность:
(161200 + 140513 х n)/(36 х 200 + 20 х 36 х n + 36 х n) = (297200 + 4513 х n)/(х n х 756 + 7200) -
Направление роста модели при увеличении количества объектов каждой сущности. Рост линейно зависит от количества пользователей.
-
Примеры данных
Breed
[ { "_id": "breed_id_1",
"image": "https://cdn2.thecatapi.com/images/ozEvzdVM-.jpg", "name": "Aegean", "parameters": { "weight_imperial": "7 - 10", "weight_metric": "3 - 5", "vetstreet_url": "http://www.vetstreet.com/cats/aegean-cat", "temperament": "Affectionate, Social, Intelligent, Playful, Active", "origin": "Greece", "country_codes": "GR", "description": "Native to the Greek islands known as the Cyclades in the Aegean Sea, these are natural cats, meaning they developed without humans getting involved in their breeding. As a breed, Aegean Cats are rare, although they are numerous on their home islands. They are generally friendly toward people and can be excellent cats for families with children.", "life_span": "9 - 12", "indoor": 0, "adaptability": 5, "affection_level": 4, "child_friendly": 4, "dog_friendly": 4, "energy_level": 3, "grooming": 3, "health_issues": 1, "intelligence": 3, "shedding_level": 3, "social_needs": 4, "stranger_friendly": 4, "vocalisation": 3, "hypoallergenic": 0 }, "comments": [ { "id": "comment_id_1", "author": "user_id_1", "parent_comments_id": null, "date": "2023-10-01T10:00:00Z", "text": "Она прекрасна!.", "likes": [ "user_id_2", "user_id_3" ] }, { "id": "comment_id_2", "author": "user_id_2", "parent_comments_id": "comment_id_1", "date": "2023-10-02T11:00:00Z", "text": "ДА!!!!", "likes": [] } ] } ]
User
[ { "_id": "user_id_1", "name": "Саша", "age": 21, "isAdmin": false, "passwordHash": "hashed_password_1", "image": "https://example.com/images/user1.jpg", "creation_date": "2023-01-01T08:00:00Z", "last_date": "2023-10-01T09:00:00Z", "favorites": [ "breed_id_1" ] } ]
Event
[
{
"_id": "event_id_1",
"user_id": "user_id_1",
"breed_id": "breed_id_1",
"type": "ADD_TO_FAVORITE",
"date": "2023-11-01T09:00:00Z"
}
]
- Примеры запросов
Добавление пользователя
db.user.insertOne({ _id: "user_id", user_name: "SASHA", "isAdmin": false, "passwordHash": "hashed_password_1", "image": "https://example.com/images/user1.jpg", "creation_date": "2023-01-01T08:00:00Z", "last_date": "2023-10-01T09:00:00Z", "favorites": [ "breed_id_1" ] });
Получение списка всех пород/фильтрация
db.breed.find({});
db.breed.find({ "parameters.activity": 5 });
Получение карточки породы (один запрос)
db.breed.findOne({ _id: "breed_id" });
Добавления комментария
db.breed.updateOne( { _id: "breed_id" }, { $push: { comments: { id: "comment_id", author: "author_id", parent_comments_id: "parent_comment_id", date: now(), text: "Смотрю на эту кошечку уже сутки!", likes: [] } } }
db.event.insertOne({user_id: "author_id", breed_id: "breed_id", type: "comment_added", date: now()});
Получение комментариев
db.breed.find( { _id: "breed_id" }, { comments: 1})
Лайк комментарию
db.breed.updateOne( { _id: "BREED_ID", "comments.id": "comment_id" }, { $addToSet: { "comments.$.likes": "user_id" } } });
db.event.insertOne({ user_id: "user_id", breed_id: "breed_id", type: "comment_liked", date: now() });
Удаление лайка
db.breed.updateOne( { _id: "BREED_ID", "comments.id": "comment_id" }, { $pull: { "comments.$.likes": "user_id" } } })
db.event.insertOne({ user_id: "user_id", breed_id: "breed_id", type: "comment_unliked", date: now() });
Профиль пользователя
db.user.findOne({ _id: "user_id" });
Изменение профиля пользователя
db.user.updateOne( { _id: "user_id" }, { $set: { name: "new_name", age: new_age, image: "url_to_new_image", last_date: now()}
Статистика
db.event.find({ user_id: "user_id", type: "comment_unliked" });
При добавлении/удалении комментариев или добавлении/удалении лайков требуется два запроса и используется две коллекции для завершения юзкейса. В остальных случаях хватает одного запроса и одной коллекции для завершения юзкейса.
Реляционная модель
- Графическое представление модели
- Описание назначений коллекций, типов данных и сущностей
Таблица Breed предназначена для хранения данных о конкретной породе. В таблице Breed хранятся идентификатор породы (внешний ключ) и различные характеристики породы, такие как вес (char(50)), описание темперамента(char(255)), общее описание породы (char(255)), страна происхождения (char(50)), энергичность(int) и тд.
Таблица Comment предназначена для хранения данных о комментариях. В таблице Comment хранятся идентификатор комментария (int), идентификатор автора комментария(int), идентификатор родительского комментария (int), идентификатор породы которой был написан комментарий (int), полная дата создания комментария(datetime), текст комментария(char(255)).
Таблица User предназначена для хранения данных о пользователях. В таблице User хранятся идентификатор пользователя (int), имя пользователя (char(50)), возраст пользователя (int), флаг админа (boolean), пароль (int), ссылка на картинку(char(50)), дата создания профиле(date), дата последнего редактирования профиля(date).
Таблица Event предназначена для хранения данных о событиях(для статистики). В таблице Event хранятся идентификатор пользователя(int), тип события(int), идентификатор породы(int), дата события(datetime).
Таблица EventType предназначена для храненая данных о типе события В таблице *EventType хранятся идентификатор пользователя(int), тип события(int), идентификатор породы(int), имя события(char(250)).
Таблица Favorite предназначена для хранения данных о любимых породах. В таблице Favorite хранятся идентификаторы пользователя(int) и породы(int).
Таблица Like предназначена для хранения данныз о понравившихся комментариях. В таблице Like хранятся идентификаторы пользователя(int) и комментария(int).
Оценка объема информации, хранимой в модели
Таблица Breed статична, количество памяти для одной породы равно 1971 байт
Количество памяти для одного комментария равно 275 байт
Количество памяти для одного пользователя равно 122 байт
Количество памяти для одного события равно 20 байт
Количество памяти для одного типа события равно 254 байт
Количество памяти для одного лайка равно 8 байт
Количество памяти для одного фаворита равно 8 байт
Среднее число пород - 200
Среднее число комментариев пользователя - 20
Среднее число любимых пород пользователя - 100
Среднее число понравившихся комментариев - 100
Среднее число событий пользователя - 1000
Формула: 1971 х 200 + (122 + 20 х 275 + 1000 х (20 + 254) + 100 х 8 + 100 х 8) х n = 394200 + 33822 х n
Избыточность данных
Избыточность модели Избыточность в таблице Breed
breed_id - 4 байта
Избыточность в таблице Comment
comment_id, author_user_id, parent_comment_id, breed_id - 16 байт
Избыточность в таблице User user_id, isAdmin - 5 байт
Таблицы Like, Favorite, Event, EventType избыточны - 298 байт
Формула: 1967 х 200 + (117 + 20 х 259) х n = 393400 + 5297 х n
Отношение между фактическим объемом и избыточным (без учета таблицы с породами) - 6,4
Направление роста модели при увеличении количества объектов каждой сущности.
При создании таблицы Favorite, Like, Comment, User - будут создаваться таблицы Event, EventType.
Примеры данных
Breed {
"id": "aege",
"weight_imperial": "7 - 10",
"weight_metric": "3 - 5”,
"name": "Aegean",
"vetstreet_url": "http://www.vetstreet.com/cats/aegean-cat",
"temperament": "Affectionate, Social, Intelligent, Playful, Active",
"origin": "Greece",
"country_codes": "GR",
"country_code": "GR",
"description": "Native to the Greek islands known as the Cyclades in the Aegean Sea, these are natural cats, meaning they developed without humans getting involved in their breeding. As a breed, Aegean Cats are rare, although they are numerous on their home islands. They are generally friendly toward people and can be excellent cats for families with children.",
"life_span": "9 - 12",
"indoor": 0,
"alt_names": "",
"adaptability": 5,
"affection_level": 4,
"child_friendly": 4,
"dog_friendly": 4,
"energy_level": 3,
"grooming": 3,
"health_issues": 1,
"intelligence": 3,
"shedding_level": 3,
"social_needs": 4,
"stranger_friendly": 4,
"vocalisation": 3,
"experimental": 0,
"hairless": 0,
"natural": 0,
"rare": 0,
"rex": 0,
"suppressed_tail": 0,
"short_legs": 0,
"wikipedia_url": "https://en.wikipedia.org/wiki/Aegean_cat",
"hypoallergenic": 0,
"reference_image_id": "ozEvzdVM-",
"image_width": 1200,
"image_height": 800,
"image_url": "https://cdn2.thecatapi.com/images/ozEvzdVM-.jpg"
}
Comment
{
“comment_id”: 0,
“author_user_id”:0,
“parent_comment_id”:null,
“breed_id_int”:0,
“creation_date”:”9999-12-31 23:59:59”
“message”:”cute”
}
User
{
“user_id”:0,
“user_name”:”Naruto”,
“user_age”:22,
“isAdmin”: false,
“password”:123456,
“image_url”:””,
“creation_date”:2001-01-01,
“last_edit_date”:2001-01-01
}
Like
{
“user_id”:0,
“comment_id”:0
}
Favorite
{
“user_id”:0,
“breed_id”:0
}
Event
{
“user_id”:0,
“type_id”:0,
“breed_id”:0,
“date”:2001-01-01
}
EventType
{
“user_id”:0,
“type_id”:0,
“breed_id”:0,
“event_name”:”comment”
}
Примеры запросов
Добавление пользователя
INSERT INTO USER (user_id, …, ) VALUES(...);
Получение списка всех пород/фильтрация
SELECT * FROM BREED;
SELECT * FROM BREED WHERE activity=5;
Получение карточки породы (один запрос)
SELECT * FROM BREED WHERE breed_id =“breed_id”;
Добавления комментария
INSERT INTO COMMENT (comment_id, author_user_id, parent_comment_id, breed_id, creation_date, message) VALUES (...);
Получение комментариев
SELECT * FROM COMMENT WHERE breed_id =”breed_id”;
Лайк комментарию
INSERT INTO LIKE (user_id, comment_id) VALUES(...);
Удаление лайка
DELETE FROM LIKE WHERE user_id =”user_id” && comment_id =”comment_id”;
Профиль пользователя
SELECT * FROM USER WHERE user_id =”user_id”;
Изменение профиля пользователя
UPDATE USER SET user_name =”user_name” … WHERE user_id =”user_id”;
Статистика
SELECT * FROM event INNER JOIN eventtype ON type_id WHERE user_id =”user_id”;
Для завершения юзкейса требуется один запрос.
Сравнение моделей
- Удельный объем информации:
При сравнении удельного объёма информации получилось, что нереляционная модель занимает 161200 + 140513 х n байтов, а реляционная модель занимает 394200 + 33822 х n байтов. Таким образом, при количестве пользователей более 2-x реляционная модель будет занимать меньше места, чем нереляционная. Так как случай с двумя и менее пользователями не представляет интереса для нашей задачи, эти случаи можно не рассматривать. - Запросы по отдельным юзкейсам: Для всех юзкейсов реляционная модель требует одного запроса, а нереляционная для части юзкейсов (добавление, уделание комментариев, добавление, удаление лайков) требует два запроса в две коллекции.
Вывод
В результате сравнения выяснилось, что для решения поставленной задачи для исследуемых характеристик(сравнение удельного объёма информации, сравнения количества запросов для юзкейсоов) реляционная модель лучше.