Skip to content

Модель данных

Евгений Мордасов edited this page Apr 6, 2025 · 10 revisions

Нереляционная модель

NoSQL модель

Примеры запросов

  1. Регистрация пользователя
db.User.insertOne({
    UniqueID: ObjectId(),
    Name: "Иван",
    Surname: "Иванов",
    Nickname: "IvanCool",
    Create_Date: new Date(),
    Last_Redact_Date: new Date(),
    email: "ivan@example.com",
    CommentIDs: [],
    hash_Password: "hashed_password"
});
  1. Авторизация пользователя (поиск по email и паролю)
db.User.findOne({
    email: "ivan@example.com",
    hash_Password: "hashed_password"
});
  1. Просмотр профиля пользователя
db.User.findOne(
    { UniqueID: ObjectId("id_пользователя") },
    { hash_Password: 0 } // Исключаем поле с паролем
);
  1. Редактирование профиля пользователя
db.User.updateOne(
    { UniqueID: ObjectId("id_пользователя") },
    {
        $set: {
            Name: "Иван",
            Surname: "Петров",
            Nickname: "IvanUpdated",
            email: "ivan.new@example.com",
            Last_Redact_Date: new Date()
        }
    }
);
  1. Добавление нового рецепта
db.Recipe.insertOne({
    RecipeID: ObjectId(),
    Title: "Борщ",
    Composition: "Свекла, капуста, картошка, мясо",
    Date: new Date(),
    Recipe: "Шаг 1: Нарежьте овощи. Шаг 2: Варите 40 минут...",
    Rate: 0,
    CommentIDs: []
});
  1. Редактирование рецепта
db.Recipe.updateOne(
    { RecipeID: ObjectId("id_рецепта") },
    {
        $set: {
            Title: "Борщ по-украински",
            Composition: "Свекла, капуста, картошка, мясо, чеснок",
            Recipe: "Обновленный способ приготовления...",
            Date: new Date()
        }
    }
);
  1. Удаление рецепта
db.Recipe.deleteOne({ RecipeID: ObjectId("id_рецепта") });
  1. Просмотр списка рецептов
db.Recipe.find({}, { Recipe: 0 }).pretty();
// Исключаем поле Recipe, чтобы не загружать всю информацию в списке
  1. Просмотр одного рецепта (с комментариями)
db.Recipe.aggregate([
    { $match: { RecipeID: ObjectId("id_рецепта") } },
    {
        $lookup: {
            from: "Comment",
            localField: "RecipeID",
            foreignField: "RecipeID",
            as: "Comments"
        }
    }
]).pretty();
  1. Добавление комментария к рецепту
let commentID = ObjectId();
db.Comment.insertOne({
    UniqueID: commentID,
    Username: "IvanCool",
    Text: "Очень вкусный борщ!",
    Rating: 5,
    Date: new Date(),
    RecipeID: ObjectId("id_рецепта"),
    Title: "Лучший борщ"
});
db.Recipe.updateOne(
    { RecipeID: ObjectId("id_рецепта") },
    { $push: { CommentIDs: commentID } }
);
  1. Редактирование комментария
db.Comment.updateOne(
    { UniqueID: ObjectId("id_комментария") },
    { $set: { Text: "Обновленный комментарий", Rating: 4, Date: new Date() } }
);
  1. Удаление комментария
db.Comment.deleteOne({ UniqueID: ObjectId("id_комментария") });
db.Recipe.updateOne(
    { RecipeID: ObjectId("id_рецепта") },
    { $pull: { CommentIDs: ObjectId("id_комментария") } }
);
  1. Поиск рецептов по названию
db.Recipe.find({ Title: { $regex: "борщ", $options: "i" } }).pretty();
  1. Фильтрация рецептов по рейтингу
db.Recipe.find({ Rate: { $gte: 4 } }).pretty();
  1. Выставление рейтинга рецепту
db.Recipe.updateOne(
    { RecipeID: ObjectId("id_рецепта") },
    { $set: { Rate: 5 } }
);

Примеры данных

Пример NoSQL

Избыточность данных

С расчетом можно ознакомиться в разделе Сравнение моделей Получились следующие значения:

  1. User: 2.26
  2. Recipe: 1.16
  3. Comment 1.04

Рассмотрим теперь рост объема базы данных от одной переменной. В среднем на нашем сайте будет 100 рецептов, n пользователей и 2n комментариев. Тогда получаем с учетом объемов каждой сущности следующую зависимость: g(n) = 100*960 + 237*n + 567*2*n = 96000 + 1371*n байт. Можно ввести понятие избыточности от одной переменной. Пусть это будет следующим отношением:

$$z(n) = \frac{100*960 + 237*n + 567*2*n}{100*828+ 105*n + 543*2*n} = \frac{96000 + 1371*n}{82800 + 1191*n} = \frac{457}{397} + \frac{272400}{397*(1191n+82800)} \approx 1,151 + 0,576*\frac{1}{n+69,521}$$

Реляционная модель

SQL модель

Примеры запросов

  1. Регистрация пользователя
INSERT INTO User (Name, Surname, NickName, email, hash_Password)
VALUES ('Имя', 'Фамилия', 'Никнейм', 'email@example.com', 123456);
  1. Авторизация пользователя
SELECT * FROM User
WHERE email = 'email@example.com' AND hash_Password = 123456;
  1. Просмотр профиля пользователя
SELECT Name, Surname, NickName, Create_Date, email
FROM User
WHERE id = 1;
  1. Редактирование профиля
UPDATE User
SET
    Name = 'Новое имя',
    Surname = 'Новая фамилия',
    NickName = 'Новый ник',
    email = 'new@example.com',
    hash_Password = 654321,
    Last_Redact_Date = CURRENT_TIMESTAMP
WHERE id = 1;
  1. Добавление нового рецепта
INSERT INTO Recipe (Title, Composition, Recipe, Rate)
VALUES ('Название рецепта', 'Ингредиенты', 'Инструкция', 5);
  1. Редактирование рецепта
UPDATE Recipe
SET
    Title = 'Новое название',
    Composition = 'Новые ингредиенты',
    Recipe = 'Новая инструкция',
    Rate = 4,
    Date = CURRENT_TIMESTAMP
WHERE id = 1;
  1. Удаление рецепта
DELETE FROM Recipe WHERE id = 1;
  1. Просмотр списка рецептов
SELECT id, Title, Date, Rate FROM Recipe
ORDER BY Date DESC;
  1. Просмотр одного рецепта (с комментариями)
SELECT * FROM Recipe WHERE id = 1;
SELECT
    Comment.Text,
    Comment.Rating,
    Comment.Date,
    User.NickName AS Author
FROM Comment
JOIN User ON Comment.UserID = User.id
WHERE Comment.RecipeID = 1;
  1. Добавление комментария
INSERT INTO Comment (Text, Rating, RecipeID, Title, UserID)
VALUES ('Текст комментария', 5, 1, 'Заголовок', 1);
  1. Редактирование комментария
UPDATE Comment
SET
    Text = 'Новый текст',
    Rating = 4,
    Date = CURRENT_TIMESTAMP
WHERE id = 1 AND UserID = 1;
  1. Удаление комментария
DELETE FROM Comment
WHERE id = 1 AND UserID = 1;
  1. Поиск рецептов по названию
SELECT * FROM Recipe
WHERE Title LIKE '%Название%';
  1. Фильтрация по рейтингу
SELECT * FROM Recipe
WHERE Rate >= 4;
  1. Выставление рейтинга рецепту
UPDATE Recipe
SET Rate = 5
WHERE id = 1;

Примеры данных

Пример SQL

Избыточность данных

С расчетом можно ознакомиться в разделе Сравнение моделей Получились следующие значения:

  1. User: 1.11
  2. Recipe: 1.01
  3. Comment 1.04

Рассмотрим теперь рост объема базы данных от одной переменной (количество пользователей). В среднем на нашем сайте будет 100 рецептов, n пользователей и 2n комментариев. Тогда получаем с учетом объемов каждой сущности следующую зависимость: g(n) = 100*840 + 117*n + 564*2*n = 84000 + 1245*n байт. Можно ввести понятие избыточности от одной переменной. Пусть это будет следующим отношением:

$$z(n) = \frac{100*840 + 117*n + 564*2*n}{100*828 + 105*n + 540*2*n} = \frac{84000 + 1245*n}{82800 + 1185*n} = \frac{83}{79} - \frac{236400}{79*(1185n+82800)} \approx 1,051 - 2,525*\frac{1}{n+69,873}$$

Сравнение моделей

Верхняя таблица отвечает за NoSQL модель, нижняя за SQL. Веса баз данных Как видно по рисунку, у Nosql удельный вес больше, чем у Sql базы данных. Обе структуры линейно возрастают с увеличением числа данных.

Количество объектов пользователей и рецептов не зависят от других, а вот количество комментариев зависит линейно от количества пользователей и линейно от количества рецептов. Т.е. количество комментариев можно представить в виде f(x,y) = ax*by. Где a и b некоторые множители, а x и y это количество пользователей и рецептов соответственно. Тогда общий рост модели будет таким: F(x,y) = ax*by+x+y (рост комментариев + рост пользователей + рост рецептов)

Опираясь на формулы для избыточности каждой модели (SQL и NoSQL) можно сделать вывод, что в общем случае избыточность реляционной БД меньше, чем нереляционной БД. Также меньше и объем данных

Количество запросов для каждой из БД:

Сценарий использования №1 - Поиск рецепта на главной странице сайта.

  • SQL: 1 запрос
  • MongoDB: 1 запрос

Сценарий использования №2 - Просмотр рецепта

  • SQL: 2 запроса
  • MongoDB: 2 запроса

Сценарий использования №3 - Оценка и отзыв на рецепт

  • SQL: 3 запроса
  • MongoDB: 3 запроса

Сценарий использования №4 - Взаимодействие с личным кабинетом, зарегистрированного пользователя

  • SQL: 3 запроса
  • MongoDB: 3 запроса

Сценарий использования №5 - Добавление рецепта

  • SQL: 1 запрос
  • MongoDB: 1 запрос

Сценарий использования №6 - Удаление рецепта

  • SQL: 1 запрос
  • MongoDB: 1-2 запроса

Сценарий использования №7 - Массовый импорт/экспорт данных

  • SQL: 1 запрос
  • MongoDB: 1 запрос

Сценарий использования №8 - Просмотр данных о пользователях и об отзывах

  • SQL: 3 запроса
  • MongoDB: 3 запроса

Сценарий использования №9 - Просмотр статистики о пользователях

  • SQL: 1 запрос
  • MongoDB: 1 запрос

Вывод

SQL база данных лучше подходит для наших задач. Она занимает имеет меньший вес и меньшую избыточность. Количество запросов должно быть относительно одинаковым.