-
Notifications
You must be signed in to change notification settings - Fork 0
Модель данных
n − максимально необходимый размер строки для текста. Оптимальное n = 500 символов.
Назначение: Хранит информацию о пользователях системы, их идентификацию и роли.
Атрибуты:
-
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 байт на пользователя
Связи:
-
Один пользователь может участвовать в нескольких проектах.
-
Один пользователь может быть отправителем или получателем нескольких сообщений.
Назначение: Хранит информацию о проектах по организации ремонта, включая этапы и задачи.
Атрибуты:
-
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 байт на пользователя
Связи:
-
Один проект может включать несколько этапов.
-
Проект содержит этапы, риски и закупки.
Назначение: Хранит информацию об этапах проекта.
Атрибуты:
-
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 байт на этап.
Связи:
-
Этап включает несколько задач.
-
Этап связан с одним проектом.
Назначение: Хранит информацию о задачах, связанных с этапами проекта.
Атрибуты:
-
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 байт на задачу.
Связи:
-
Задача может быть связана с несколькими рабочими через связь многие ко многим.
-
Задача может быть связана с этапом через связь один ко многим.
Назначение: Хранит информацию о сообщениях между пользователями.
Атрибуты:
-
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 байт на сообщение.
Связи:
-Одно сообщение может быть отправлено одним пользователем и направлено другому пользователю.
Назначение: Хранит информацию о закупках материалов для проектов.
Атрибуты:
-
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 байт на сообщение.
Связи:
- Одна закупка привязана к одному проекту.
Назначение: Хранит информацию о рисках, связанных с проектами.
Атрибуты:
-
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 байт на риск
Связи:
- Один проект может иметь несколько рисков.
Назначение: Хранит информацию о пользователях и проектах, в которых они участвуют.
Атрибуты:
-
id (PK) — уникальный идентификатор контакта, тип: INT (4 байта)
-
user_id (FK) — идентификатор пользователя, тип: INT (4 байта)
-
project_id (FK) — идентификатор проекта, тип: INT (4 байта)
-
created_at — Время создания записи контакта. Это поле автоматически фиксирует дату и время, когда учетная запись контакта была создана в системе, тип TIMESTAMP (8 байт)
-
updated_at — Время последнего обновления записи контакта. Это поле автоматически обновляется при каждом изменении данных контакта, тип TIMESTAMP (8 байт)
Общий размер: приблизительно 28 байт на контакт
Связи:
- Один контакт связывает пользователя с проектом.
Назначение: Хранит информацию о пользователях и проектах, в которых они участвуют.
Атрибуты:
-
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) ничего создаваться дополнительно не будет
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
Примеры запросов
- Регистрация пользователя
Запрос на регистрацию пользователя:
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;
- Написание сообщения
Запрос на поиск пользователя по фамилии, имени или должности:
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());
- Просмотр графика работы
Запрос на получение задач рабочего:
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;
- Создание проекта
Запрос на создание проекта:
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;
- Просмотр и правка проекта
Запрос на просмотр информации о проекте:
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;
- Оформление закупки
Запрос на добавление материалов в закупки:
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;
- Создание рисков
Запрос на добавление рисков проекта:
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;
- Создание контактов
Запрос на добавление контакта в проект:
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;
- Создание и редактирование этапов
Запрос на добавление этапа проекта:
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;
- Создание и редактирование задач
Запрос на создание задачи:
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;
- Массовый Импорт/Экспорт графика
Запрос на экспорт данных проекта для анализа:
COPY projects TO '/path/projects.csv' WITH (FORMAT csv, HEADER);
Запрос на импорт данных в проект:
COPY projects FROM '/path/projects.csv' WITH (FORMAT csv, HEADER);
- Получение статистики
Получение статистики по рискам
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';
Картинка
{
"_id": "ObjectID", // Уникальный идентификатор
"surname": "String", // Фамилия пользователя
"name": "String", // Имя пользователя
"father_name": "String", // Отчество пользователя
"username": "String", // Логин пользователя
"password": "String", // Хеш пароля
"role": "String", // Роль пользователя (можно также использовать ENUM-подобную логику с набором ролей)
"created_at": "ISODate", // Дата создания
"updated_at": "ISODate", // Дата последнего обновления
}
{
"_id": "ObjectId", // Уникальный идентификатор проекта
"name": "String", // Название проекта
"description": "String", // Описание проекта
"start_date": "ISODate", // Дата начала проекта
"end_date": "ISODate", // Дата окончания проекта
"status": "String", // Статус проекта (в работе/завершён)
"created_at": "ISODate", // Дата создания
"updated_at": "ISODate", // Дата последнего обновления
"contacts": [{ // Контакты пользователей
"_id": "ObjectId", // Уникальный идентификатор контакта
"user_id": "ObjectId", // Идентификатор пользователя
"role": "String"
}],
"stages": [ // Список этапов проекта
{
"stage_id": "ObjectId", // Идентификатор этапа
"name": "String", // Название этапа
"start_date": "ISODate", // Дата начала этапа
"end_date": "ISODate", // Дата окончания этапа
"created_date": "ISODate", // Дата создания этапа
"updated_at": "ISODate", // Дата обновления
"task": "[ObjectID]", // сылки на задачи
}
],
"risks": [ // Список рисков проекта
{
"risk_id": "ObjectId", // Идентификатор риска
"name": "String", // Название риска
"description": "String" // Описание риска
"created_date": "ISODate", // Дата создания риска
"updated_at": "ISODate" // Дата обновления
}
],
"procurements": ["ObjectID"] // ссылки на закупки
}
{
"_id": "ObjectId", // Уникальный идентификатор сообщения
"text": "String", // Текст сообщения
"sent_date": "ISODate", // Дата отправки
"sender_id": "ObjectId", // Идентификатор отправителя
"receiver_id": "ObjectId", // Идентификатор получателя
"created_date": "ISODate", // Дата создания сообщения
"updated_at": "ISODate" // Дата обновления
"status": "String" // Статус сообщения (прочитано/непрочитано)
}
{
"_id": "ObjectId", // Уникальный идентификатор этапа
"name": "String", // Название этапа
"start_date": "ISODate", // Дата начала этапа
"end_date": "ISODate", // Дата окончания этапа
"created_date": "ISODate", // Дата создания этапа
"updated_at": "ISODate" // Дата обновления
"tasks": ["ObjectID"] // Список задач этапа
}
{
"_id": "ObjectId", // Уникальный идентификатор закупки
"item_name": "String", // Наименование товара
"quantity": "Number", // Количество товара
"price": "Number", // Цена товара
"created_date": "ISODate", // Дата создания закупки
"updated_at": "ISODate" // Дата обновления
"project_id": "ObjectId" // Идентификатор связанного проекта
}
{
"_id": "ObjectId", // Уникальный идентификатор риска
"name": "String", // Название риска
"description": "String", // Описание риска
"created_at": "ISODate", // Дата создания
"updated_at": "ISODate" // Дата обновления
}
{
"_id": "ObjectId", // Уникальный идентификатор контакта
"user_id": "ObjectId", // Идентификатор пользователя
"project_id": "ObjectId", // Идентификатор проекта
"created_at": "ISODate", // Дата создания контакта
"updated_at": "ISODate" // Дата обновления
}
"tasks": [ // Список задач в рамках этапа
{
"_id": "ObjectId", // Идентификатор задачи
"name": "String", // Название задачи
"description": "String", // Описание задачи
"start_date": "ISODate", // Дата начала задачи
"end_date": "ISODate", // Дата окончания задачи
"status": "String", // Статус задачи (запланировано/в работе/завершено)
"created_at": "ISODate", // Дата создания задачи
"updated_at": "ISODate", // Дата обновления
"workers": [ // Список рабочих, ответственных за задачу
{
"user_id": "ObjectId", // Идентификатор рабочего
"name": "String" // Имя рабочего
}
]
}
]
Предположительно пользователь будет создавать:
-
заказчиков в среднем u
-
в среднем прорабов u
-
в среднем работников 8*u
-
в среднем 1*u проектов
-
в среднем 3 этапа на проект
-
в среднем 5 задач на этап
-
в среднем 105u рассылок + 630u сообщений между пользователями
-
в среднем 100 закупок на проект
-
в среднем 8 рабочих + 1 прораб+ 1 заказчик на проект
-
в среднем 5 рисков на проект
{
"_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 байт.
{
"_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 байт
{
"_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 байт
{
"_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 байт
{
"_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 байт
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 рисков на проект
{
"surname": "String": 500 байт,
"name": "String": 500 байт,
"father_name": "String": 500 байт,
"username": "String": 500 байт,
"password": "String": 500 байт,
"role": "String": 50 байт,
}
- Общий размер: приблизительно 2550 байт.
{
"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 байт
{
"text": "String": 500 байт,
"sent_date": "ISODate": 8 байт,
"sender_id": "ObjectId": 12 байт,
"receiver_id": "ObjectId": 12 байт,
"status": "String": 10 байт
}
- Общий размер: приблизительно 542 байт
{
"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 байт
{
"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
Модель представленных данных демонстрирует несколько направлений роста, каждое из которых может влиять на общую архитектуру и производительность системы. Вот ключевые направления:
- С увеличением числа пользователей растет объем данных, что требует эффективного управления идентификаторами, паролями и ролями.
- Каждое новое добавление пользователя увеличивает объем дублированных данных, например, при хранении информации о проектах и сообщениях, связанных с пользователями.
- Каждому пользователю может быть присвоено несколько проектов, что приводит к увеличению общего объема данных.
- Увеличение количества проектов в системе требует обработки связанной информации, такой как этапы, риски и закупки, что добавляет дополнительные слои сложности.
- С увеличением числа проектов и этапов возникает необходимость в более сложной структуре для управления задачами.
- Увеличение числа задач может привести к необходимости более детальной оценки статусов и сроков выполнения, что также увеличивает объем данных.
- По мере роста количества пользователей и проектов возрастает и объем сообщений между ними. Это может привести к увеличению нагрузки на систему и потребовать оптимизации хранения и обработки данных.
- С увеличением числа проектов и их сложностью увеличивается необходимость в управлении рисками и закупками. Это требует создания более детализированных записей и статусов для рисков и закупок, что увеличивает общий объем данных.
- Увеличение числа связей между пользователями, проектами, этапами, задачами, рисками и закупками требует эффективного управления этими связями.
- С увеличением связей увеличивается сложность запросов и операций в базе данных, что может повлиять на производительность.
- Каждое новое добавление пользователя, проекта или задачи может привести к экспоненциальному увеличению избыточности данных, особенно если данные дублируются в разных коллекциях.
- Это создает необходимость в реализации методов нормализации данных и стратегий управления дублирующимися записями, чтобы минимизировать избыточность.
{
"_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")
}
{
"_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")]
}
{
"_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")
]
}
{
"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": "Сергей Кузнецов"
}
]
}
]
}
{
"text": "Привет! Это пример сообщения для MongoDB. В этом сообщении может быть до 500 байт текста. Это позволяет передавать достаточно много информации в одном сообщении.",
"sent_date": ISODate("2023-10-01T12:34:56Z"),
"sender_id": ObjectId("60f1b8d4e138234068a9099a"),
"receiver_id": ObjectId("60f1b8d4e138234068a9099b"),
"status": "delivered"
}
{
"_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")
}
{
"_id": ObjectId("60c72b2f9c3d4d1234567890"),
"name": "Задержка поставок",
"description": "Возможная задержка поставок оборудования, что может привести к задержке проекта.",
"created_at": ISODate("2023-01-01T00:00:00Z"),
"updated_at": ISODate("2023-01-15T00:00:00Z")
}
{
"_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)
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)
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)
vs1 запрос (NoSQL)
-
Создание проекта:
1 запрос в (SQL)
vs1 запрос (NoSQL)
-
Создание риска:
1 запрос в (SQL)
vs1 запрос (NoSQL)
-
Поиск сообщений:
1 запрос в (SQL)
vs1 запрос (NoSQL)
-
Получение статистики:
1 запрос в (SQL)
vs1 запрос (NoSQL)
-
Регистрация/Авторизация:
1 (SQL)
vs1(NoSQL)
-
Создание проекта:
1 (SQL)
vs1 (NoSQL)
-
Создание риска:
1 (SQL)
vs1 (NoSQL)
-
Поиск сообщений:
1 (SQL)
vs1 (NoSQL)
-
Получение статистики:
1 (SQL)
vs1 (NoSQL)
На основе проведённого анализа можно сделать следующие выводы для данного проекта:
-
Удельный объём информации: Реляционная модель данных обладает меньшим объёмом хранения, чем нереляционная. Это позволяет более эффективно использовать дисковое пространство за счёт минимизации дублирования данных.
-
Количество запросов: Обе модели демонстрируют приблизительно одинаковые результаты по количеству запросов, необходимых для выполнения основных юзкейсов, что свидетельствует о схожей производительности при обращении к данным.
-
Число используемых коллекций: Нереляционная модель позволяет уменьшить количество задействованных коллекций за счёт встроенной поддержки сложных структур данных, что может упростить некоторые аспекты разработки.
Несмотря на то, что MongoDB (нереляционная модель) может упростить архитектуру запросов и снизить нагрузку на уровне приложений, она требует более тщательного управления бизнес-логикой в самой базе данных. Это может привести к усложнению разработки и снижению гибкости при масштабировании приложения.
С учётом этих факторов реляционная модель на базе SQL выглядит предпочтительнее для данного проекта, так как она позволяет более эффективно использовать ресурсы и облегчает поддержку приложения в долгосрочной перспективе.