Skip to content

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

Galenko Aleksey edited this page Nov 7, 2024 · 13 revisions

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

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

PostgreSQL

sql

Коллекции и сущности

n − максимально необходимый размер строки для текста. Оптимальное n = 500 символов.

Пользователь (User)

Назначение: Хранит информацию о пользователях системы, их идентификацию и роли.

Атрибуты:

  • id (PK) — уникальный идентификатор пользователя, тип: INT (4 байта)

  • surname — фамилия пользователя, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • name — имя пользователя, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • lastname — отчество пользователя, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • username — уникальный логин для входа, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • password — зашифрованный пароль пользователя, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • role — роль пользователя в системе (Администратор, Прораб, Рабочий, Заказчик), тип: ENUM (1 байт (считаем 4 возможных значения))

  • created_at — Время создания записи пользователя. Это поле автоматически фиксирует дату и время, когда учетная запись пользователя была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи пользователя. Это поле автоматически обновляется при каждом изменении данных пользователя, тип TIMESTAMP (8 байт)

Общий размер: приблизительно 5n+31 байт на пользователя

Связи:

  • Один пользователь может участвовать в нескольких проектах.

  • Один пользователь может быть отправителем или получателем нескольких сообщений.

Проект (Project)

Назначение: Хранит информацию о проектах по организации ремонта, включая этапы и задачи.

Атрибуты:

  • id (PK) — уникальный идентификатор проекта, тип: INT (4 байта)

  • name — название проекта, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • description — описание проекта, тип: TEXT (до n+2 байт (n символов + служебная информация))

  • start_date — дата начала проекта, тип: DATE (3 байта)

  • end_date — дата окончания проекта, тип: DATE (3 байта)

  • status — статус проекта (в работе, завершён), тип: ENUM (1 байт (считаем 4 возможных значения))

  • contact_id (FK) — идентификатор контактов (ссылка на контакты), тип: INT (4 байта)

  • created_at — Время создания записи проекта. Это поле автоматически фиксирует дату и время, когда учетная запись проекта была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи проекта. Это поле автоматически обновляется при каждом изменении данных проекта, тип TIMESTAMP (8 байт)

Общий размер: приблизительно 2n+41 байт на пользователя

Связи:

  • Один проект может включать несколько этапов.

  • Проект содержит этапы, риски и закупки.

Этап (Stage)

Назначение: Хранит информацию об этапах проекта.

Атрибуты:

  • id (PK) — уникальный идентификатор этапа, тип: INT (4 байта)

  • name — название этапа, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • start_date — дата начала этапа, тип: DATE (3 байта)

  • end_date — дата окончания этапа, тип: DATE (3 байта)

  • project_id (FK) — идентификатор проекта, к которому относится этап, тип: INT (4 байта)

  • created_at — Время создания записи этапа. Это поле автоматически фиксирует дату и время, когда учетная запись этапа была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи этапа. Это поле автоматически обновляется при каждом изменении данных этапа, тип TIMESTAMP (8 байт)

  • Общий размер: приблизительно n+32 байт на этап.

Связи:

  • Этап включает несколько задач.

  • Этап связан с одним проектом.

Задача (Task)

Назначение: Хранит информацию о задачах, связанных с этапами проекта.

Атрибуты:

  • id (PK) — уникальный идентификатор задачи, тип: INT (4 байта)

  • name — название задачи, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • description — описание задачи, тип: TEXT (до n+2 байт (n символов + служебная информация))

  • start_date — дата начала задачи, тип: DATE (3 байта)

  • end_date — дата окончания задачи, тип: DATE (3 байта)

  • status — статус задачи (запланировано, в работе, завершено), тип: ENUM (1 байт)

  • stage_id (FK) — идентификатор этапа, к которому относится задача, тип: INT (4 байта)

  • contact_id (FK) — идентификатор рабочего, ответственного за задачу, тип: INT (4 байта)

  • created_at — Время создания записи задачи. Это поле автоматически фиксирует дату и время, когда учетная запись задачи была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи задачи. Это поле автоматически обновляется при каждом изменении данных задачи, тип TIMESTAMP (8 байт)

Общий размер: приблизительно 2n+39 байт на задачу.

Связи:

  • Задача может быть связана с несколькими рабочими через связь многие ко многим.

  • Задача может быть связана с этапом через связь один ко многим.

Сообщение (Message)

Назначение: Хранит информацию о сообщениях между пользователями.

Атрибуты:

  • id (PK) — уникальный идентификатор сообщения, тип: INT (4 байта)

  • text — текст сообщения, тип: TEXT (до n+2 байт (n символов + служебная информация))

  • sent_date — дата отправки сообщения, тип: DATETIME (8 байт)

  • sender_id (FK) — идентификатор отправителя (ссылка на пользователя), тип: INT (4 байта)

  • receiver_id (FK) — идентификатор получателя (ссылка на пользователя), тип: INT (4 байта)

  • status — статус сообщения (прочитано или нет), тип: ENUM (1 байт)

  • created_at — Время создания записи сообщения. Это поле автоматически фиксирует дату и время, когда учетная запись сообщения была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи сообщения. Это поле автоматически обновляется при каждом изменении данных сообщения, тип TIMESTAMP (8 байт)

Общий размер: приблизительно n+39 байт на сообщение.

Связи:

-Одно сообщение может быть отправлено одним пользователем и направлено другому пользователю.

Закупка (Procurement)

Назначение: Хранит информацию о закупках материалов для проектов.

Атрибуты:

  • id (PK) — уникальный идентификатор закупки, тип: INT (4 байта)

  • item_name — наименование закупаемого товара, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • quantity — количество товара, тип: INT (4 байта)

  • price — цена товара, тип: DECIMAL (8 байт)

  • created_date — дата создания закупки, тип: TIMESTAMP (8 байт)

  • project_id (FK) — идентификатор проекта, связанного с закупкой, тип: INT (4 байта)

  • created_at — Время создания записи закупки. Это поле автоматически фиксирует дату и время, когда учетная запись закупки была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи закупки. Это поле автоматически обновляется при каждом изменении данных закупки, тип TIMESTAMP (8 байт)

Общий размер: приблизительно n+46 байт на сообщение.

Связи:

  • Одна закупка привязана к одному проекту.

Риск (Risk)

Назначение: Хранит информацию о рисках, связанных с проектами.

Атрибуты:

  • id (PK) — уникальный идентификатор риска, тип: INT (4 байта)

  • name — название риска, тип: VARCHAR (до n+2 байт (n символов + служебная информация))

  • description — описание риска, тип: TEXT (до n+2 байт (n символов + служебная информация))

  • project_id (FK) — идентификатор проекта, к которому относится риск, тип: INT (4 байта)

  • created_at — Время создания записи риски. Это поле автоматически фиксирует дату и время, когда учетная запись риска была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи риска. Это поле автоматически обновляется при каждом изменении данных риска, тип TIMESTAMP (8 байта)

Общий размер: приблизительно 2n+ 28 байт на риск

Связи:

  • Один проект может иметь несколько рисков.

Контакт (Contact)

Назначение: Хранит информацию о пользователях и проектах, в которых они участвуют.

Атрибуты:

  • id (PK) — уникальный идентификатор контакта, тип: INT (4 байта)

  • user_id (FK) — идентификатор пользователя, тип: INT (4 байта)

  • project_id (FK) — идентификатор проекта, тип: INT (4 байта)

  • created_at — Время создания записи контакта. Это поле автоматически фиксирует дату и время, когда учетная запись контакта была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи контакта. Это поле автоматически обновляется при каждом изменении данных контакта, тип TIMESTAMP (8 байт)

Общий размер: приблизительно 28 байт на контакт

Связи:

  • Один контакт связывает пользователя с проектом.

Работник_Задача (User_Task)

Назначение: Хранит информацию о пользователях и проектах, в которых они участвуют.

Атрибуты:

  • id (PK) — уникальный идентификатор контакта, тип: INT (4 байта)

  • user_id (FK) — идентификатор пользователя, тип: INT (4 байта)

  • task_id (FK) — идентификатор задачи, тип: INT (4 байта)

  • created_at — Время создания записи таблицы. Это поле автоматически фиксирует дату и время, когда учетная запись в таблицу была создана в системе, тип TIMESTAMP (8 байт)

  • updated_at — Время последнего обновления записи в таблицу. Это поле автоматически обновляется при каждом изменении данных таблицы, тип TIMESTAMP (8 байт)

Общий размер: приблизительно 28 байт на таблицу Работник_Задача

Связи:

  • Много задач связаны с многими работниками.

Оценка удельного объема информации

Средний размер одного документа коллекции:

  • User: 5n+3 + 24 (оверхед строки) = 2527 байт

  • Project: 2n+41 +24 (оверхед строки) = 1065 байт

  • Stage: n+32 = 532 байт

  • Task: 2n+39 + 24 (оверхед строки) = 1063 байт

  • Message: n+39+ 24 (оверхед строки) = 563 байт

  • Procurement: n+46 = 546 байт

  • Risk: 2n+ 28 + 24 (оверхед строки) = 1052 байт

  • Contact: 28 байт

Предположительно пользователь будет создавать:

  • заказчиков в среднем u

  • в среднем прорабов u

  • в среднем работников 8*u

  • в среднем 1*u проектов

  • в среднем 3 этапа на проект

  • в среднем 5 задач на этап

  • в среднем 105u рассылок + 630u сообщений между пользователями

  • в среднем 100 закупок на проект

  • в среднем 8 рабочих + 1 прораб+ 1 заказчик на проект

  • в среднем 5 рисков на проект

При количестве заказчиков равным u:

V(u)=(252710 +735563+1065+3532+106315+100546+51052+10*28) ∗u= 516221∗u

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

  • В таблице User: избыточные данные id, created_at, updated_at (20 байт)

  • В таблице Project: избыточные данные id, created_at, updated_at, project_id (24 байт)

  • В таблице Stage: избыточные данные id, created_at, updated_at, project_id (24 байт)

  • В таблице Task: избыточные данные id, created_at, updated_at, stage_id, worker_id (28 байт)

  • В таблице Message: избыточные данные id, created_at, updated_at, receiver_id, sender_id (28 байт)

  • В таблице Procurement: избыточные данные id, created_at, updated_at, project_id (24 байт)

  • В таблице Risk: избыточные данные id, created_at, updated_at, project_id (24 байт)

  • В таблице Contact: избыточные данные вся таблица.

При количестве заказчиков равным u:

Vclean(u)=(250710 +1041+3508+103515+735535+100522+51028) ∗u=493625∗u

Тогда рассчитаем избыточность как отношение объема модели к "чистому" объему:

V(u)/Vclean(u)=516221∗u/493625∗u≈1,0457

Направление роста модели

При создании модели Project будут создаваться модели Stage, Task, Procurement, Risk, Contact

При добавлении других моделей (User, Message) ничего создаваться дополнительно не будет

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

Таблица User

id surname name lastname username password role created_at updated_at
1 Иванов Иван Иванович ivanov_ivan e5d3be45bfeabc Администратор 2024-10-10 09:00:00 2024-10-10 09:00:00
2 Смирнова Анна Сергеевна smirnova_anna 9aaf7cc6dce123 Заказчик 2024-10-12 10:20:00 2024-10-12 10:20:00
3 Петров Петр Петрович petrov_petr c23b5d7f4fa2d7 Прораб 2024-10-13 11:30:00 2024-10-13 11:30:00
4 Сидоров Сергей Викторович sidorov_sergey f12e9873df129a Рабочий 2024-10-14 12:15:00 2024-10-14 12:15:00

Таблица Project

id name description start_date end_date status customer_id foreman_id created_at updated_at
1 Ремонт офиса Проект по ремонту офисного здания 2024-11-01 2024-12-20 в работе 2 3 2024-10-12 10:25:00 2024-10-12 10:25:00
2 Строительство склада Строительство складского помещения 2024-11-15 2025-01-30 в работе 2 3 2024-10-13 11:35:00 2024-10-13 11:35:00

Таблица Task

id name description start_date end_date status stage_id worker_id created_at updated_at
1 Установка розеток Монтаж электророзеток в офисе 2024-11-16 2024-11-17 запланировано 2 4 2024-10-14 12:20:00 2024-10-14 12:20:00
2 Укладка плитки Укладка плитки в санузлах офиса 2024-11-18 2024-11-20 запланировано 2 4 2024-10-14 12:25:00 2024-10-14 12:25:00

Таблица Stage

id name start_date end_date project_id created_at updated_at
1 Дизайн интерьера 2024-11-01 2024-11-15 1 2024-10-12 10:30:00 2024-10-12 10:30:00
2 Электромонтажные работы 2024-11-16 2024-11-30 1 2024-10-13 11:40:00 2024-10-13 11:40:00

Таблица Message

id text sent_date sender_id receiver_id status created_at updated_at
1 Здравствуйте, когда начнется проект? 2024-10-12 10:30:00 2 3 прочитано 2024-10-12 10:30:00 2024-10-12 10:30:00
2 Утверждаю смету 2024-10-13 11:35:00 2 3 не прочитано 2024

Таблица Procurement

id item_name quantity price created_date project_id created_at updated_at
1 Электрические кабели 1000 50000 2024-10-15 14:00:00 1 2024-10-15 14:00:00 2024-10-15 14:00:00
2 Плитка керамическая 500 30000 2024-10-16 10:15:00 1 2024-10-16 10:15:00 2024-10-16 10:15:00

Таблица Contact

id user_id project_id created_at updated_at
1 2 1 2024-10-12 10:50:00 2024-10-12 10:50:00
2 3 1 2024-10-12 10:51:00 2024-10-12 10:51:00

Таблица Item

id item_name quantity price created_date project_id created_at updated_at
1 Электрические кабели 1000 50000 2024-10-15 14:00:00 1 2024-10-15 14:00:00 2024-10-15 14:00:00
2 Плитка керамическая 500 30000 2024-10-16 10:15:00 1 2024-10-16 10:15:00 2024-10-16 10:15:00

Таблица Risk

id name description project_id created_at updated_at
1 Задержка поставки материалов Возможная задержка поставок 1 2024-10-12 10:40:00 2024-10-12 10:40:00
2 Отсутствие рабочей силы Нехватка работников для укладки плитки 1 2024-10-13 11:45:00 2024-10-13 11:45:00

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

1. Регистрация пользователя

Запрос на регистрацию пользователя:

INSERT INTO users (username, password_hash, email, role_id)
VALUES (:username, :password_hash, :email, :role_id);

Запрос на получение роли пользователя:

SELECT role_id FROM roles WHERE role_name = :role_name;

Запрос на создание логина и пароля:

UPDATE users SET password_hash = :password_hash WHERE email = :email;

2. Написание сообщения

Запрос на поиск пользователя по фамилии, имени или должности:

SELECT * FROM users WHERE last_name = :last_name OR first_name = :first_name OR position = :position;

Запрос на отправку сообщения:

INSERT INTO messages (chat_id, sender_id, content, timestamp) 
VALUES (:chat_id, :sender_id, :content, NOW());

Запрос получение сообщений от пользователя:

INSERT INTO messages (chat_id, sender_id, content, timestamp) 
VALUES (:chat_id, :sender_id, :content, NOW());

3. Просмотр графика работы

Запрос на получение задач рабочего:

SELECT * FROM tasks WHERE assigned_worker_id = :worker_id 
AND (status = 'active' OR status = 'in_progress');

Запрос на фильтрацию задач:

SELECT * FROM tasks WHERE project_id = :project_id AND status = :status AND task_date BETWEEN :start_date AND :end_date;

4. Создание проекта

Запрос на создание проекта:

INSERT INTO projects (name, description, client_id, start_date, end_date, status) 
VALUES (:name, :description, :client_id, :start_date, :end_date, 'pending');

Запрос на назначение прораба на проект:

UPDATE projects SET foreman_id = :foreman_id WHERE project_id = :project_id;

5. Просмотр и правка проекта

Запрос на просмотр информации о проекте:

SELECT * FROM projects WHERE project_id = :project_id;

Запрос на редактирование проекта:

UPDATE projects SET description = :description, start_date = :start_date, end_date = :end_date WHERE project_id = :project_id;

6. Оформление закупки

Запрос на добавление материалов в закупки:

INSERT INTO purchases (project_id, item_name, quantity, unit_price)
VALUES (:project_id, :item_name, :quantity, :unit_price);

Запрос на редактирование закупки:

UPDATE purchases SET item_name = :item_name, quantity = :quantity, unit_price = :unit_price WHERE purchase_id = :purchase_id;

7. Создание рисков

Запрос на добавление рисков проекта:

INSERT INTO risks (project_id, risk_name, description)
VALUES (:project_id, :risk_name, :description);

Запрос на редактирование риска:

UPDATE risks SET risk_name = :risk_name, description = :description WHERE risk_id = :risk_id;

8. Создание контактов

Запрос на добавление контакта в проект:

INSERT INTO project_contacts (project_id, user_id) 
VALUES (:project_id, :user_id);

Запрос на удаление контакта:

DELETE FROM project_contacts WHERE project_id = :project_id AND user_id = :user_id;

9. Создание и редактирование этапов

Запрос на добавление этапа проекта:

INSERT INTO stages (project_id, stage_name, start_date, end_date) 
VALUES (:project_id, :stage_name, :start_date, :end_date);

Запрос на редактирование этапа:

UPDATE stages SET stage_name = :stage_name, start_date = :start_date, end_date = :end_date WHERE stage_id = :stage_id;

10. Создание и редактирование задач

Запрос на создание задачи:

INSERT INTO tasks (stage_id, task_name, start_date, end_date, worker_id, status) 
VALUES (:stage_id, :task_name, :start_date, :end_date, :worker_id, 'pending');

Запрос на редактирование задачи:

UPDATE tasks SET task_name = :task_name, start_date = :start_date, end_date = :end_date, status = :status WHERE task_id = :task_id;

11. Массовый Импорт/Экспорт графика

Запрос на экспорт данных проекта для анализа:

COPY projects TO '/path/projects.csv' WITH (FORMAT csv, HEADER);

Запрос на импорт данных в проект:

COPY projects FROM '/path/projects.csv'  WITH (FORMAT csv, HEADER);

12. Получение статистики

Получение статистики по рискам

SELECT *
FROM risks
WHERE project_id IN ('60f1b8d4e138234068a9099a', '60f1b8d4e138234068a9099b')
  AND created_date BETWEEN '2023-01-01' AND '2023-12-31';

Получение статистики по закупкам

SELECT *
FROM procurements
WHERE project_id IN ('60f1b8d4e138234068a9099a', '60f1b8d4e138234068a9099b')
AND created_date BETWEEN '2023-01-01' AND '2023-12-31';

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

MongoDB

nosql

Картинка

Коллекции и сущности

1. Пользователь (User)

{
  "_id": "ObjectID",                               // Уникальный идентификатор
  "surname": "String",                   // Фамилия пользователя
  "name": "String",                      // Имя пользователя
  "father_name": "String",               // Отчество пользователя
  "username": "String",                  // Логин пользователя
  "password": "String",                  // Хеш пароля
  "role": "String",                      // Роль пользователя (можно также использовать ENUM-подобную логику с набором ролей)
  "created_at": "ISODate",               // Дата создания
  "updated_at": "ISODate",               // Дата последнего обновления
}

2. Проект (Project)

{
  "_id": "ObjectId",                     // Уникальный идентификатор проекта
  "name": "String",                      // Название проекта
  "description": "String",               // Описание проекта
  "start_date": "ISODate",               // Дата начала проекта
  "end_date": "ISODate",                 // Дата окончания проекта
  "status": "String",                    // Статус проекта (в работе/завершён)
  "created_at": "ISODate",               // Дата создания
  "updated_at": "ISODate",               // Дата последнего обновления
  
  "contacts": {                          // Контакты, связанные с проектом
    "contact_id_1": {
      "user_id": "ObjectId",             // Идентификатор пользователя
      "created_at": "ISODate",           // Дата создания контакта
      "updated_at": "ISODate"            // Дата обновления контакта
    },
    "contact_id_2": {
      "user_id": "ObjectId",
      "created_at": "ISODate",
      "updated_at": "ISODate"
    }
  },

  "stages": {                            // Этапы проекта
    "stage_id_1": {
      "name": "String",                  // Название этапа
      "start_date": "ISODate",           // Дата начала этапа
      "end_date": "ISODate",             // Дата окончания этапа
      "created_date": "ISODate",         // Дата создания этапа
      "updated_at": "ISODate",           // Дата обновления этапа
      "tasks": {                         // Задачи этапа
        "task_id_1": {
          "name": "String",              // Название задачи
          "description": "String",       // Описание задачи
          "start_date": "ISODate",       // Дата начала задачи
          "end_date": "ISODate",         // Дата окончания задачи
          "status": "String",            // Статус задачи
          "created_at": "ISODate",
          "updated_at": "ISODate",
          "workers": {
            "worker_id_1": {             // Рабочий, назначенный на задачу
              "user_id": "ObjectId",     // Идентификатор пользователя
              "name": "String"           // Имя рабочего
            }
          }
        }
      }
    }
  },

  "risks": {                             // Риски, связанные с проектом
    "risk_id_1": {
      "name": "String",                  // Название риска
      "description": "String",           // Описание риска
      "created_at": "ISODate",           // Дата создания риска
      "updated_at": "ISODate"            // Дата обновления риска
    },
    "risk_id_2": {
      "name": "String",
      "description": "String",
      "created_at": "ISODate",
      "updated_at": "ISODate"
    }
  },

  "procurements": {                      // Закупки, связанные с проектом
    "procurement_id_1": {
      "item_name": "String",             // Наименование товара
      "quantity": "Number",              // Количество товара
      "price": "Number",                 // Цена товара
      "created_by": "ObjectId",          // Идентификатор пользователя, создавшего закупку
      "created_date": "ISODate",         // Дата создания закупки
      "updated_at": "ISODate",           // Дата обновления закупки
      "delivery_date": "ISODate"         // Дата поставки товара
    },
    "procurement_id_2": {
      "item_name": "String",
      "quantity": "Number",
      "price": "Number",
      "created_by": "ObjectId",
      "created_date": "ISODate",
      "updated_at": "ISODate",
      "delivery_date": "ISODate"
    }
  }
}

3. Сообщение (Message)

{
  "_id": "ObjectId",                     // Уникальный идентификатор сообщения
  "text": "String",                      // Текст сообщения
  "sent_date": "ISODate",                // Дата отправки
  "sender_id": "ObjectId",               // Идентификатор отправителя
  "receiver_id": "ObjectId",             // Идентификатор получателя
  "created_date": "ISODate",                // Дата создания сообщения 
  "updated_at": "ISODate"                   // Дата обновления
  "status": "String"                     // Статус сообщения (прочитано/непрочитано)
}

4. Этап (Stage)

{
  "_id": "ObjectId",                     // Уникальный идентификатор этапа
  "name": "String",                      // Название этапа
  "start_date": "ISODate",               // Дата начала этапа
  "end_date": "ISODate",                 // Дата окончания этапа
  "created_date": "ISODate",             // Дата создания этапа 
  "updated_at": "ISODate",               // Дата последнего обновления
  "tasks": {                             // Список задач этапа
    "task_id_1": {
      "name": "String",                  // Название задачи
      "description": "String",           // Описание задачи
      "start_date": "ISODate",           // Дата начала задачи
      "end_date": "ISODate",             // Дата окончания задачи
      "status": "String",                // Статус задачи (запланировано/в работе/завершено)
      "created_at": "ISODate",           // Дата создания задачи
      "updated_at": "ISODate",           // Дата обновления задачи
      "workers": {                       // Список рабочих, ответственных за задачу
        "worker_id_1": {
          "user_id": "ObjectId",         // Идентификатор рабочего
          "name": "String"               // Имя рабочего
        }
      }
    }
  }
}

5. Закупка (Procurement)

{
  "_id": "ObjectId",                     // Уникальный идентификатор закупки
  "item_name": "String",                 // Наименование товара
  "quantity": "Number",                  // Количество товара
  "price": "Number",                     // Цена товара
  "created_date": "ISODate",                // Дата создания закупки
  "updated_at": "ISODate"                   // Дата обновления
  "project_id": "ObjectId"               // Идентификатор связанного проекта
}

6. Риск (Risk)

{
  "_id": "ObjectId",                     // Уникальный идентификатор риска
  "name": "String",                      // Название риска
  "description": "String",               // Описание риска
  "created_at": "ISODate",                  // Дата создания
  "updated_at": "ISODate"                   // Дата обновления
}

7. Контакт (Contact)

{
  "_id": "ObjectId",                     // Уникальный идентификатор контакта
  "user_id": "ObjectId",                 // Идентификатор пользователя
  "project_id": "ObjectId",              // Идентификатор проекта
  "created_at": "ISODate",                  // Дата создания контакта
  "updated_at": "ISODate"                   // Дата обновления
}

8. Задачи (Task)

{
  "tasks": {                            // Словарь задач в рамках этапа
    "task_id_1": {                      // Идентификатор задачи
      "name": "String",                 // Название задачи
      "description": "String",          // Описание задачи
      "start_date": "ISODate",          // Дата начала задачи
      "end_date": "ISODate",            // Дата окончания задачи
      "status": "String",               // Статус задачи (запланировано/в работе/завершено)
      "created_at": "ISODate",          // Дата создания задачи
      "updated_at": "ISODate",          // Дата обновления задачи
      "workers": {                      // Список рабочих, ответственных за задачу
        "worker_id_1": {                // Идентификатор рабочего
          "user_id": "ObjectId",        // Идентификатор пользователя
          "name": "String"              // Имя рабочего
        },
        "worker_id_2": {
          "user_id": "ObjectId",
          "name": "String"
        }
      }
    },
    "task_id_2": {
      "name": "String",
      "description": "String",
      "start_date": "ISODate",
      "end_date": "ISODate",
      "status": "String",
      "created_at": "ISODate",
      "updated_at": "ISODate",
      "workers": {
        "worker_id_1": {
          "user_id": "ObjectId",
          "name": "String"
        }
      }
    }
  }
}

Оценка удельного объема информации

Средний размер одного документа коллекции:

Предположительно пользователь будет создавать:

  • заказчиков в среднем u

  • в среднем прорабов u

  • в среднем работников 8*u

  • в среднем 1*u проектов

  • в среднем 3 этапа на проект

  • в среднем 5 задач на этап

  • в среднем 105u рассылок + 630u сообщений между пользователями

  • в среднем 100 закупок на проект

  • в среднем 8 рабочих + 1 прораб+ 1 заказчик на проект

  • в среднем 5 рисков на проект

User:

{
  "_id": "ObjectId": 12 байт,
  "surname": "String": 500 байт,
  "name": "String": 500 байт,
  "father_name": "String": 500 байт,
  "username": "String": 500 байт,
  "password": "String": 500 байт,
  "role": "String": 50 байт,
  "created_at": "ISODate": 8 байт,
  "updated_at": "ISODate": 8 байт
}
  • Общий размер: приблизительно 2578 байт.

Project:

{
  "_id": "ObjectId": 12 байт,
  "name": "String": 500 байт,
  "description": "String": 1000 байт,
  "start_date": "ISODate": 8 байт,
  "end_date": "ISODate": 8 байт,
  "status": "String": 50 байт,
  "created_at": "ISODate": 8 байт,
  "updated_at": "ISODate": 8 байт,
  "contacts": [{ // Предположим 8 контакта
    "_id": "ObjectId": 12 байт,
    "user_id": "ObjectId": 12 байт,
    "project_id": "ObjectId": 12 байт,
    "created_at": "ISODate": 8 байт,
    "updated_at": "ISODate": 8 байт
  }] * 8 = (12 * 8 + 12 * 8 + 12 * 8 + 8 * 8 + 8 * 8) = 416 байт,
  "stages": [{ // Предположим 3 этапов
    "stage_id": "ObjectId": 12 байт,
    "name": "String": 500 байт,
    "start_date": "ISODate": 8 байт,
    "end_date": "ISODate": 8 байт,
    "created_date": "ISODate": 8 байт,
    "updated_at": "ISODate": 8 байт,
    "task": "[ObjectId]": 12 байт * 5 задач
  }] * 3 = (12 * 3 + 500 * 3 + 8 * 3 + 8 * 3 + 8 * 3 + 8 * 3 + 12 * 3 * 5) = 1812 байт,
  "risks": [{ // Предположим 5 риска
    "risk_id": "ObjectId": 12 байт,
    "name": "String": 500 байт,
    "description": "String": 1000 байт,
    "created_date": "ISODate": 8 байт,
    "updated_at": "ISODate": 8 байт
  }] * 5 = (12 * 5 + 500 * 5 + 1000 * 5 + 8 * 5 + 8 * 5) = 7640 байт,
  "procurements": ["ObjectId"]: 12 байт * 50 = 600 байт
}
  • Общий размер: приблизительно 12062 байт

Message:

{
  "_id": "ObjectId": 12 байт,
  "text": "String": 500 байт,
  "sent_date": "ISODate": 8 байт,
  "sender_id": "ObjectId": 12 байт,
  "receiver_id": "ObjectId": 12 байт,
  "created_date": "ISODate": 8 байт,
  "updated_at": "ISODate": 8 байт,
  "status": "String": 10 байт
}
  • Общий размер: приблизительно 570 байт

Task:

{
  "_id": "ObjectId": 12 байт,
  "name": "String": 500 байт,
  "description": "String": 1000 байт,
  "start_date": "ISODate": 8 байт,
  "end_date": "ISODate": 8 байт,
  "status": "String": 50 байт,
  "created_at": "ISODate": 8 байт,
  "updated_at": "ISODate": 8 байт,
  "workers": [{ // Предположим 3 работника
    "user_id": "ObjectId": 12 байт,
    "name": "String": 500 байт
  }] * 3 = (12 * 3 + 500 * 3) = 1536 байт
}
  • Общий размер: приблизительно 3130 байт

Procurement:

{
  "_id": "ObjectId": 12 байт,
  "item_name": "String": 500 байт,
  "quantity": "Number": 8 байт,
  "price": "Number": 8 байт,
  "created_date": "ISODate": 8 байт,
  "updated_at": "ISODate": 8 байт,
  "project_id": "ObjectId": 12 байт
}
  • Общий размер: приблизительно 556 байт

При количестве заказчиков равным u:

V(u)=(257810 + 12062+735570+153130+556100)∗u= 560342∗u

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

Предположительно пользователь будет создавать:

  • заказчиков в среднем u

  • в среднем прорабов u

  • в среднем работников 8*u

  • в среднем 1*u проектов

  • в среднем 3 этапа на проект

  • в среднем 5 задач на этап

  • в среднем 105u рассылок + 630u сообщений между пользователями

  • в среднем 100 закупок на проект

  • в среднем 8 рабочих + 1 прораб+ 1 заказчик на проект

  • в среднем 5 рисков на проект

User:

{
  "surname": "String": 500 байт,
  "name": "String": 500 байт,
  "father_name": "String": 500 байт,
  "username": "String": 500 байт,
  "password": "String": 500 байт,
  "role": "String": 50 байт,
}
  • Общий размер: приблизительно 2550 байт.

Project:

{
  "name": "String": 500 байт,
  "description": "String": 1000 байт,
  "start_date": "ISODate": 8 байт,
  "end_date": "ISODate": 8 байт,
  "status": "String": 50 байт,
  "stages": [{ // Предположим 3 этапов
    "name": "String": 500 байт,
    "start_date": "ISODate": 8 байт,
    "end_date": "ISODate": 8 байт,
  }] * 3 = (500 * 3 + 8 * 3 + 8 * 3) = 1548 байт,
  "risks": [{ // Предположим 5 риска
    "name": "String": 500 байт,
    "description": "String": 1000 байт,
  }] * 5 = (500 * 5 + 1000 * 5) = 7500 байт,
}
  • Общий размер: приблизительно 10114 байт

Message:

{
  "text": "String": 500 байт,
  "sent_date": "ISODate": 8 байт,
  "sender_id": "ObjectId": 12 байт,
  "receiver_id": "ObjectId": 12 байт,
  "status": "String": 10 байт
}
  • Общий размер: приблизительно 542 байт

Task:

{
  "name": "String": 500 байт,
  "description": "String": 1000 байт,
  "start_date": "ISODate": 8 байт,
  "end_date": "ISODate": 8 байт,
  "status": "String": 50 байт,
  "workers": [{ // Предположим 3 работника
    "name": "String": 500 байт
  }] * 3 = (500 * 3) = 1500 байт
}
  • Общий размер: приблизительно 3066 байт

Procurement:

{
  "item_name": "String": 500 байт,
  "quantity": "Number": 8 байт,
  "price": "Number": 8 байт,
}
  • Общий размер: приблизительно 516 байт

Vclean(u)=(255010 + 10014+735542+153066+516100)∗u =531474∗u

Тогда рассчитаем избыточность как отношение объема модели к "чистому" объему:

V(u)/Vclean(u)=560342∗u/531474 ∗u≈1,054

Направление роста модели

Модель представленных данных демонстрирует несколько направлений роста, каждое из которых может влиять на общую архитектуру и производительность системы. Вот ключевые направления:

Рост количества пользователей (User)

  • С увеличением числа пользователей растет объем данных, что требует эффективного управления идентификаторами, паролями и ролями.
  • Каждое новое добавление пользователя увеличивает объем дублированных данных, например, при хранении информации о проектах и сообщениях, связанных с пользователями.

Рост числа проектов (Project)

  • Каждому пользователю может быть присвоено несколько проектов, что приводит к увеличению общего объема данных.
  • Увеличение количества проектов в системе требует обработки связанной информации, такой как этапы, риски и закупки, что добавляет дополнительные слои сложности.

Расширение функционала этапов (Stage) и задач (Task)

  • С увеличением числа проектов и этапов возникает необходимость в более сложной структуре для управления задачами.
  • Увеличение числа задач может привести к необходимости более детальной оценки статусов и сроков выполнения, что также увеличивает объем данных.

Увеличение количества сообщений (Message)

  • По мере роста количества пользователей и проектов возрастает и объем сообщений между ними. Это может привести к увеличению нагрузки на систему и потребовать оптимизации хранения и обработки данных.

Расширение структуры рисков (Risk) и закупок (Procurement)

  • С увеличением числа проектов и их сложностью увеличивается необходимость в управлении рисками и закупками. Это требует создания более детализированных записей и статусов для рисков и закупок, что увеличивает общий объем данных.

Рост связей между сущностями

  • Увеличение числа связей между пользователями, проектами, этапами, задачами, рисками и закупками требует эффективного управления этими связями.
  • С увеличением связей увеличивается сложность запросов и операций в базе данных, что может повлиять на производительность.

Экспоненциальный рост избыточности данных

  • Каждое новое добавление пользователя, проекта или задачи может привести к экспоненциальному увеличению избыточности данных, особенно если данные дублируются в разных коллекциях.
  • Это создает необходимость в реализации методов нормализации данных и стратегий управления дублирующимися записями, чтобы минимизировать избыточность.

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

1. Пользователь (User)

{
  "_id": ObjectId("60c72b2f9c3d4d1234567890"),
  "surname": "Иванов",
  "name": "Иван",
  "father_name": "Иванович",
  "username": "ivanov_i",
  "password": "$2a$10$CwF5W.x5Bz4L.D1BZj/R7e.OW2iWO5NOhp7M7N5QAn3ceWDhSEzy6", // Пример хеша пароля
  "role": "Администратор",
  "created_at": ISODate("2023-01-01T00:00:00Z"),
  "updated_at": ISODate("2023-01-15T00:00:00Z")
}

2. Проект (Project)

{
  "_id": ObjectId("60c72b2f9c3d4d1234567890"),
  "name": "Проект XYZ",
  "description": "Разработка нового веб-приложения для управления проектами.",
  "start_date": ISODate("2023-01-01T00:00:00Z"),
  "end_date": ISODate("2023-12-31T00:00:00Z"),
  "status": "в работе",
  "created_at": ISODate("2022-12-01T00:00:00Z"),
  "updated_at": ISODate("2023-01-15T00:00:00Z"),
  "contacts": [
    {
      "_id": ObjectId("60c72b2f9c3d4d1234567891"),
      "user_id": ObjectId("60c72b2f9c3d4d1234567892"),
      "role": "Менеджер проекта"
    },
    {
      "_id": ObjectId("60c72b2f9c3d4d1234567893"),
      "user_id": ObjectId("60c72b2f9c3d4d1234567894"),
      "role": "Разработчик"
    }
  ],
  "stages": [
    {
      "stage_id": ObjectId("60c72b2f9c3d4d1234567895"),
      "name": "Планирование",
      "start_date": ISODate("2023-01-01T00:00:00Z"),
      "end_date": ISODate("2023-02-01T00:00:00Z"),
      "created_date": ISODate("2023-01-01T00:00:00Z"),
      "updated_at": ISODate("2023-01-10T00:00:00Z"),
      "task": [ObjectId("60c72b2f9c3d4d1234567896")]
    },
    {
      "stage_id": ObjectId("60c72b2f9c3d4d1234567897"),
      "name": "Разработка",
      "start_date": ISODate("2023-02-02T00:00:00Z"),
      "end_date": ISODate("2023-05-01T00:00:00Z"),
      "created_date": ISODate("2023-02-02T00:00:00Z"),
      "updated_at": ISODate("2023-02-15T00:00:00Z"),
      "task": [ObjectId("60c72b2f9c3d4d1234567898")]
    }
  ],
  "risks": [
    {
      "risk_id": ObjectId("60c72b2f9c3d4d1234567899"),
      "name": "Задержка поставок",
      "description": "Возможная задержка поставок оборудования.",
      "created_date": ISODate("2023-01-05T00:00:00Z"),
      "updated_at": ISODate("2023-01-10T00:00:00Z")
    },
    {
      "risk_id": ObjectId("60c72b2f9c3d4d1234567900"),
      "name": "Недостаток ресурсов",
      "description": "Возможный недостаток человеческих ресурсов.",
      "created_date": ISODate("2023-01-06T00:00:00Z"),
      "updated_at": ISODate("2023-01-12T00:00:00Z")
    }
  ],
  "procurements": [ObjectId("60c72b2f9c3d4d1234567901")]
}

3. Этап (Stage)

{
  "_id": ObjectId("60c72b2f9c3d4d1234567890"),
  "name": "Планирование",
  "start_date": ISODate("2023-01-01T00:00:00Z"),
  "end_date": ISODate("2023-02-01T00:00:00Z"),
  "created_date": ISODate("2023-01-01T00:00:00Z"),
  "updated_at": ISODate("2023-01-15T00:00:00Z"),
  "tasks": [
    ObjectId("60c72b2f9c3d4d1234567891"),
    ObjectId("60c72b2f9c3d4d1234567892")
  ]
}

4. Задача (Task)

{
  "tasks": [
    {
      "_id": ObjectId("60c72b2f9c3d4d1234567890"),
      "name": "Разработка модуля аутентификации",
      "description": "Создание и тестирование модуля аутентификации для веб-приложения.",
      "start_date": ISODate("2023-10-01T00:00:00Z"),
      "end_date": ISODate("2023-10-15T00:00:00Z"),
      "status": "в работе",
      "created_at": ISODate("2023-09-25T00:00:00Z"),
      "updated_at": ISODate("2023-10-05T00:00:00Z"),
      "workers": [
        {
          "user_id": ObjectId("60c72b2f9c3d4d1234567891"),
          "name": "Иван Иванов"
        },
        {
          "user_id": ObjectId("60c72b2f9c3d4d1234567892"),
          "name": "Петр Петров"
        }
      ]
    },
    {
      "_id": ObjectId("60c72b2f9c3d4d1234567893"),
      "name": "Тестирование интерфейса",
      "description": "Проведение тестирования пользовательского интерфейса на различных устройствах.",
      "start_date": ISODate("2023-10-16T00:00:00Z"),
      "end_date": ISODate("2023-10-25T00:00:00Z"),
      "status": "запланировано",
      "created_at": ISODate("2023-09-28T00:00:00Z"),
      "updated_at": ISODate("2023-10-01T00:00:00Z"),
      "workers": [
        {
          "user_id": ObjectId("60c72b2f9c3d4d1234567894"),
          "name": "Анна Сидорова"
        },
        {
          "user_id": ObjectId("60c72b2f9c3d4d1234567895"),
          "name": "Сергей Кузнецов"
        }
      ]
    }
  ]
}

5. Сообщение (Message)

{
  "text": "Привет! Это пример сообщения для MongoDB. В этом сообщении может быть до 500 байт текста. Это позволяет передавать достаточно много информации в одном сообщении.",
  "sent_date": ISODate("2023-10-01T12:34:56Z"),
  "sender_id": ObjectId("60f1b8d4e138234068a9099a"),
  "receiver_id": ObjectId("60f1b8d4e138234068a9099b"),
  "status": "delivered"
}


6. Закупка (Procurement)

{
  "_id": ObjectId("671a1ef95632d41f5b2f6162"),
  "item_name": "Краска",
  "quantity": 100,
  "price": 5000,
  "created_date": ISODate("2024-10-22T12:31:53.412Z"),
  "updated_at": ISODate("2024-10-22T12:31:53.412Z"),
  "project_id": ObjectId("671a1ef85632d41f5b2f615f")
}

7. Риск (Risk)

{
  "_id": ObjectId("60c72b2f9c3d4d1234567890"),
  "name": "Задержка поставок",
  "description": "Возможная задержка поставок оборудования, что может привести к задержке проекта.",
  "created_at": ISODate("2023-01-01T00:00:00Z"),
  "updated_at": ISODate("2023-01-15T00:00:00Z")
}

8. Контакт (Contact)

{
  "_id": ObjectId("60c72b2f9c3d4d1234567890"),
  "user_id": ObjectId("60c72b2f9c3d4d1234567891"),
  "project_id": ObjectId("60c72b2f9c3d4d1234567892"),
  "created_at": ISODate("2023-01-01T00:00:00Z"),
  "updated_at": ISODate("2023-01-15T00:00:00Z")
}

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

Авторизация пользователя

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def authenticate_user(username, password):
    hashed_password = hash_password(password)
    query = {'username': username, 'password': hashed_password}
    user = users_collection.find_one(query)

    if user:
        return user
    else:
        return None

username = 'ivanovi'
password = 'password123'

user = authenticate_user(username, password)

Добавление пользователя

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_user(surname, name, father_name, username, password, role):
    users_collection = db['users']
    user = {
        "_id": ObjectId(),
        "surname": surname,
        "name": name,
        "father_name": father_name,
        "username": username,
        "password": password,
        "role": role,
        "created_at": datetime.utcnow(),
        "updated_at": datetime.utcnow()
    }
    users_collection.insert_one(user)

create_user("Иванов", "Иван", "Иванович", "ИванИ", "hashed_password", "admin")

Создание проекта

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_project(name, description, start_date, end_date, status):
    projects_collection = db['projects']
    project = {
        "_id": ObjectId(),
        "name": name,
        "description": description,
        "start_date": start_date,
        "end_date": end_date,
        "status": status,
        "created_at": datetime.utcnow(),
        "updated_at": datetime.utcnow(),
        "contacts": [],
        "stages": [],
        "risks": [],
        "procurements": []
    }
    projects_collection.insert_one(project)

create_project("Project 1", "Description of Project 1", 
                datetime.utcnow(), datetime.utcnow(), "in progress")

Создание задачи

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_task(name, description, start_date, end_date, status, workers):
    tasks_collection = db['tasks']
    task = {
        "_id": ObjectId(),
        "name": name,
        "description": description,
        "start_date": start_date,
        "end_date": end_date,
        "status": status,
        "created_at": datetime.utcnow(),
        "updated_at": datetime.utcnow(),
        "workers": workers
    }
    tasks_collection.insert_one(task)

create_task(
  "Task 1", 
  "Description of Task 1", 
  datetime.utcnow(), 
  datetime.utcnow(), 
  "planned", 
  [{"user_id": ObjectId(), "name": "John Doe"}]
)

Добавление пользователя в задачу

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def add_worker_to_task(task_id, user_id, user_name):
    tasks_collection = db['tasks']
    query = {'_id': ObjectId(task_id)}
    update = {
        '$push': {
            'workers': {
                'user_id': ObjectId(user_id),
                'name': user_name
            }
        },
        '$set': {
            'updated_at': datetime.utcnow()
        }
    }
    tasks_collection.update_one(query, update)


task_id = '60f1b8d4e138234068a9099a'
user_id = '60f1b8d4e138234068a9099b'
user_name = 'ИванИ'

add_worker_to_task(task_id, user_id, user_name)

Создание сообщения

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_message(text, sender_id, receiver_id, status):
    messages_collection = db['messages']
    message = {
        "_id": ObjectId(),
        "text": text,
        "sent_date": datetime.utcnow(),
        "sender_id": sender_id,
        "receiver_id": receiver_id,
        "created_date": datetime.utcnow(),
        "updated_at": datetime.utcnow(),
        "status": status
    }
    messages_collection.insert_one(message)

create_message("Hello, this is a test message.", ObjectId(), ObjectId(), "unread")

Поиск сообщений

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def find_messages_by_sender(sender_id):
    messages_collection = db['messages']
    query = {'sender_id': ObjectId(sender_id)}
    messages = messages_collection.find(query)
    return list(messages)

create_message("Hello, this is a test message.", ObjectId(), ObjectId(), "unread")

Создание риска

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_risk(name, description):
    risks_collection = db['risks']
    risk = {
        "_id": ObjectId(),
        "name": name,
        "description": description,
        "created_at": datetime.utcnow(),
        "updated_at": datetime.utcnow()
    }
    risks_collection.insert_one(risk)

create_risk("Risk 1", "Description of Risk 1")

Создание закупки

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def create_procurement(item_name, quantity, price, project_id):
    procurements_collection = db['procurements']
    procurement = {
        "_id": ObjectId(),
        "item_name": item_name,
        "quantity": quantity,
        "price": price,
        "created_date": datetime.utcnow(),
        "updated_at": datetime.utcnow(),
        "project_id": project_id
    }
    procurements_collection.insert_one(procurement)

create_procurement("Item 1", 10, 100.0, ObjectId())

Получение статистики

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']

# ...

def get_statistics(stat_type, project_ids, start_date, end_date):
    if stat_type not in ['risks', 'procurements']:
        raise ValueError("Неподдерживаемый тип статистики. Поддерживаемые типы: 'risks', 'procurements'.")

    query = {
        'project_id': {'$in': [ObjectId(pid) for pid in project_ids]},
        'created_date': {
            '$gte': start_date,
            '$lte': end_date
        }
    }

    if stat_type == 'risks':
        collection = db['risks']
    elif stat_type == 'procurements':
        collection = db['procurements']

    statistics = collection.find(query)
    return list(statistics)

roject_ids = ['60f1b8d4e138234068a9099a', '60f1b8d4e138234068a9099b']  # Замените на реальные ObjectId проектов
start_date = datetime(2023, 1, 1)
end_date = datetime(2023, 12, 31)

# Получение статистики по рискам
risk_statistics = get_statistics('risks', project_ids, start_date, end_date)

# Получение статистики по закупкам
procurement_statistics = get_statistics('procurements', project_ids, start_date, end_date)

Импорт на примере коллекции projects

import json
from pymongo import MongoClient
from datetime import datetime
from bson import ObjectId


client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']
projects_collection = db['projects']

def convert_date_strings(data):
    for item in data:
        for key in ['start_date', 'end_date', 'created_at', 'updated_at']:
            if key in item:
                try:
                    item[key] = datetime.strptime(item[key], '%Y-%m-%dT%H:%M:%SZ')
                except ValueError:
                    raise ValueError(f"Некорректный формат даты для поля {key}: {item[key]}")
        if '_id' in item:
            item['_id'] = ObjectId(item['_id'])
    return data

def validate_data(data):
    required_fields = ['_id', 'name', 'description', 'start_date', 'end_date', 'status', 'created_at', 'updated_at']
    for item in data:
        for field in required_fields:
            if field not in item:
                raise ValueError(f"Отсутствует обязательное поле {field} в элементе: {item}")
    return data

# Чтение данных из JSON-файла
with open('data.json', 'r') as file:
    data = json.load(file)

# Преобразование строки даты в объект datetime
data = validate_data(data)
data = convert_date_strings(data)
projects_collection.insert_many(data)

Экспорт на примере коллекции projects

import json
from pymongo import MongoClient
from datetime import datetime
from bson import ObjectId

client = MongoClient('mongodb://localhost:27017/')
db = client['repair-db']
projects_collection = db['projects']

def convert_datetime_to_string(data):
    for item in data:
        for key in ['start_date', 'end_date', 'created_at', 'updated_at']:
            if key in item and isinstance(item[key], datetime):
                item[key] = item[key].strftime('%Y-%m-%dT%H:%M:%SZ')
        if '_id' in item:
            item['_id'] = str(item['_id'])
    return data


data = list(projects_collection.find())
data = convert_datetime_to_string(data)


with open('exported_projects.json', 'w') as file:
    json.dump(data, file, indent=4)

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

Удельный объем информации

Реляционная модель данных обычно имеет меньший удельный объем информации по сравнению с нереляционной. Это связано с тем, что в нереляционных системах данные часто дублируются для уменьшения числа обращений к базе данных, что приводит к избыточности. В реляционной модели используются разные таблицы для хранения связанных данных, что требует больше времени на объединение (JOIN) при сложных запросах, но обеспечивает более компактное хранение и минимизацию дублирования. Выбор между реляционной и нереляционной моделями зависит от требований системы, таких как скорость доступа или целостность данных.

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

  • для модели User:  2578 байт(NoSQL) | 2527 байт(SQL)

  • для модели Project: 12062 байт(NoSQL) | 11253 байт(SQL)

  • для модели Task: 3130 байт(NoSQL) | 1063 байт(SQL)

  • для модели Message: 570 байт(NoSQL) | 563 байт(SQL)

  • для модели Procurement: 556 байт(NoSQL) | 546 байт(SQL)

Запросы по отдельным юзкейсам

В нереляционной модели количество запросов для выполнения юзкейсов остаётся неизменным, независимо от количества объектов в базе данных. В реляционной модели с увеличением числа объектов количество запросов может возрастать.

Сравнения количества запросов для отдельных юзкейсов

  • Регистрация/Авторизация: 1 запрос в (SQL) vs 1 запрос (NoSQL)

  • Создание проекта: 1 запрос в (SQL) vs 1 запрос (NoSQL)

  • Создание риска: 1 запрос в (SQL) vs 1 запрос (NoSQL)

  • Поиск сообщений: 1 запрос в (SQL) vs 1 запрос (NoSQL)

  • Получение статистики: 1 запрос в (SQL) vs 1 запрос (NoSQL)

Количество задействованных коллекций

  • Регистрация/Авторизация: 1 (SQL) vs 1(NoSQL)

  • Создание проекта: 1 (SQL) vs 1 (NoSQL)

  • Создание риска: 1 (SQL) vs 1 (NoSQL)

  • Поиск сообщений: 1 (SQL) vs 1 (NoSQL)

  • Получение статистики: 1 (SQL) vs 1 (NoSQL)

Вывод

На основе проведённого анализа можно сделать следующие выводы для данного проекта:

  • Удельный объём информации: Реляционная модель данных обладает меньшим объёмом хранения, чем нереляционная. Это позволяет более эффективно использовать дисковое пространство за счёт минимизации дублирования данных.

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

  • Число используемых коллекций: Нереляционная модель позволяет уменьшить количество задействованных коллекций за счёт встроенной поддержки сложных структур данных, что может упростить некоторые аспекты разработки.

Несмотря на то, что MongoDB (нереляционная модель) может упростить архитектуру запросов и снизить нагрузку на уровне приложений, она требует более тщательного управления бизнес-логикой в самой базе данных. Это может привести к усложнению разработки и снижению гибкости при масштабировании приложения.

С учётом этих факторов реляционная модель на базе SQL выглядит предпочтительнее для данного проекта, так как она позволяет более эффективно использовать ресурсы и облегчает поддержку приложения в долгосрочной перспективе.

Clone this wiki locally