Skip to content

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

Максим Овчинников edited this page Nov 19, 2024 · 33 revisions

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

Графическое представление

nosql схема

client {

_id: ObjectID,
name: String,
surname: String,
email: String,
password: String,
orders: Array of ObjectID,
phone: String,
image: String,
createdAt: Date,
editedAt: Date

}


order {

_id: ObjectID,
tools: Array of Object,
startLeasing: Date (dd/mm/yyyy),
endLeasing: Date (dd/mm/yyyy),
price: Double,
client: Object,
deliveryType: String,
deliveryState: String,
paymentType: String,
paymentState: String,
createOrderTime: Date (dd/mm/yyyy hh:min),
relatedWorker: Object

}


worker {

_id: ObjectID,
name: String,
surname: String,
email: String,
phone: String,
image: String,
jobTitle: String,
state: String,
date: Date (dd/mm/yyyy),
orders: Array of Object,
createdAt: Date,
editedAt: Date

}


tool {

_id: ObjectID,
name: String,
dailyPrice: Double,
images: Array of String,
features: Array of String,
reviews: Array of ObjectID,
rating: Double,
ordersNumber: int32,
category: String,
type: String,
description: String
totalPrice: Double
createdAt: Date
editedAt: Date

}


review {

_id: ObjectID,
toolId: ObjectID,
reviewerId: ObjectID,
rating: Double,
date: Date (dd/mm/yyyy),
text: String

}

Описание назначений коллекций, типов данных и сущностей

БД содержит следующие коллекции:

client - коллекция для хранения данных клиентов.

  • _id - уникальный идентификатор клиента;
  • name - имя клиента;
  • surname - фамилия клиента;
  • email - почта клиента;
  • password - пароль клиента;
  • orders - заказы клиента;
  • phone - контактный телефон клиента;
  • image - изображение клиента в виде URI ссылки;
  • createdAt - дата создания аккаунта;
  • editedAt - дата последнего изменения аккаунта;


order - коллекция для хранения данных о заказах.

  • _id - уникальный идентификатор заказа;
  • tools - список инструментов в заказе;
    • toolName - наименование инструмента;
    • toolNumber - идентификатор инструмента;
  • startLeasing - дата начала аренды;
  • endLeasing - дата окончания аренды;
  • price - цена заказа;
  • client - клиента, сделавший заказ;
    • name - имя
    • surname - фамилия
    • phone - номер телефона
  • deliveryType - тип доставки (SELFPICKUP, DOOE_DELIVERY);
  • deliveryState - статус доставки (IN_WAREHOUSE, ON_WAY, DELIVERED, PICKED_UP);
  • paymentType - тип оплаты (CASH, CARD, SBP);
  • paymentState - статус оплаты (NOT_PAID, PAID, IN_PROCESS);
  • createOrderTime - время создания заказа;
  • relatedWorker - работник, отвечающий за заказ;
    • name - имя
    • surname - фамилия
    • phone - номер телефона


worker - коллекция для хранения данных сотрудников.

  • _id - уникальный идентификатор работника;
  • name - имя работника;
  • surname - фамилия работника;
  • email - почта работника;
  • phone - контактный телефон работника;
  • image - изображение клиента в виде URI ссылки;
  • jobTitle - должность;
  • state - текущий статус работника;
  • date - дата начала работы;
  • orders - заказы работника;
    • orderNumber - номер заказа
    • tools - инструменты в заказе
      • toolName - название инструмента
      • toolNumber - идентификатор инструмента;
  • createdAt - дата создания аккаунта;
  • editedAt - дата последнего изменения аккаунта;


tool - коллекция для хранения данных о инструментах.

  • _id - уникальный идентификатор инструмента;
  • name - название инструмента;
  • dailyprice - цена аренды инструмента за день;
  • images - список изображений инструмента в бинарном виде;
  • features - ассоциативный массив характеристик инструмента;
  • reviews - список отзывов о инструменте;
    • reviewer - клиент, оставивший отзыв
      • name - имя
      • surname - фамилия
      • phone - номер телефона
    • rating - оставленная оценка
    • text - содержание отзыва
  • rating - оценка инструмента;
  • ordersNumber - количество заказов на инструмент;
  • category - категория инструмента;
  • type - тип инструмента;
  • totalPrice - цена инструмента;
  • description - описание инструмента;
  • createdAt - дата добавления инструмента;
  • condition - состояние инструмента (LESS_THAT_HUNDRED_USES, LESS_THAN_THOUSAND_USES, OLD);


review - коллекция для хранения отзывов о инструментах.

  • _id - уникальный идентификатор отзыва;
  • tool - инструмент, на который оставлен отзыв;
    • toolName - название инструмента
    • toolId - идентификатор инструмента
  • reviewer - пользователь, оставивший отзыв;
    • name - имя
    • surname - фамилия
    • phone - номер телефона
  • rating - оценка инструмента;
  • date - дата отзыва;
  • text - текст отзыва;

Оценка объема информации, хранимой в модели

Коллекция client. Пусть на одного клиента приходится 5 заказов (в том числе неактивных). Тогда, для хранения x клиентов понадобится:

$$ x*(12 + 15 + 15 + 30 + 12 + 60 + 12 + 500000 + 8 + 8) = 500172x $$

  • _id - ObjectID V = 12 байт
  • name - String V = 15 байт
  • surname - String V = 15 байт
  • email - String V = 30 байт
  • password - String V = 12 байт
  • orders - Array V = 12*5 = 60 байт
  • phone - String V = 12 байт
  • image - Binary Data (предположим, что средний размер изображения составляет 500 Кб) V = 500000 байт
  • createdAt - Date V = 8 байт
  • editedAt - Date V = 8 байт

Коллекция order. Допустим, что в у каждого клиента 2 заказа, в каждом заказе 3 инструмента. Тогда:

$$ 2x(12 + 60 + 8 + 8 + 8 + 36 + 12 + 12 + 12 + 12) = 360x $$

  • _id - ObjectID V = 12 байт
  • tools - Array V = 3*(12 + 8) = 60 байт
  • startLeasing - Date V = 8 байт
  • endLeasing - Date V = 8 байт
  • price - Double V = 8 байт
  • client - Object V = (12+12+12) = 36 байт
  • deliveryType - String V = 12 байт
  • deliveryState - String V = 12 байт
  • paymentType - String V = 12 байт
  • paymentState - String V = 12 байт

Коллекция worker. Пусть на каждого работника приходится 10 клиентов. Тогда:

$$ (x/10 + 1)*(12 + 15 + 15 + 15 + 15 + 15 + 15 + 8 + 240 + 8 + 8) = 37x + 370 $$

  • _id - ObjectID V = 12 байт
  • name - String V = 15 байт
  • surname - String V = 15 байт
  • email - String V = 15 байт
  • phone - String V = 15 байт
  • jobTitle - String V = 15 байт
  • state - String V = 15 байт
  • date - Date V = 8 байт
  • orders - Array V = 5*(8+2*(12 + 8)) = 240 байт
  • createdAt - Date V = 8 байт
  • editedAt - Date V = 8 байт

Коллекция tool. Допустим, что у каждого инструмента есть 3 характеристики, 5 картинок и 50 отзывов, а всего существует 100 инструментов. Тогда:

$$ 100*(12 + 8 + 250000 + 36 + 3400 + 8 + 12 + 12 + 8 + 8 + 12) = 25351600 $$

  • _id - ObjectID V = 12 байт
  • dailyPrice - Double V = 8 байт
  • images - Array (предположим, что средний размер изображения составляет 50 Кб) V = 5*50000 = 250000 байт
  • features - Array V = 12*3 = 36 байт
  • reviews - Array V = 50 * ((12+12+12) + 8 + 24) = 3400 байт
  • rating - Double V = 8 байт
  • category - String V = 12 байт
  • type - String V = 12 байт
  • createdAt - Date V = 8 байт
  • totalPrice - Double V = 8 байт
  • condition - String V = 12 байт

Коллекция review:

$$ 100*(12 + 20 + 36 + 8 + 100) = 17600 $$

  • _id - ObjectID V = 12 байт
  • tool - Object V = 12 + 8 = 20 байт
  • reviewer - Object V = 12 + 12 + 12 = 36 байт
  • rating - Double V = 8 байт
  • date - Date V = 8 байт
  • text - String V = 100 байт

Общая оценка объема данных для x клиентов:

$$ V(x) = 500172x + 360x + 37x + + 25351600 + 7400 + 17600 = 500569x + 25351600 $$

Для грубой оценки:

$$ V(x) = 500569x $$

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

В БД у клиентов может не быть картинки (пусть в среднем у 1 из 2 клиентов будет картинка, тогда средний размер будет равен половине от изначального). Тогда получаем:

$$ V(x) = 250201x + 360x + 35x + 250090600 = 250296x + 25351600 $$

Отношение между фактическим и "чистым" объемом (отбросив свободный член) равно

$$ \frac{500569x}{250296x} = 1.9 $$

Направление роста модели при увеличении количества объектов каждой сущности

Выразим объём БД через количество клиентов x: $$ V(x) = 500596x + 250090600 $$ Виден линейный рост зависимости объёма базы данных от количества клиентов.

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

eZVCUKz3nr0 zoeo09mesdA 0UrcVwpvzRI wxf2k2jmZjU ytk7CXqKh48

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

  • регистрация нового клиента
db.client.insert({
    _id: ObjectId(),
    name: "Иван",
    surname: "Иванов",
    email: "[email protected]",
    password: "password",
    orders: [],
    phone: "+79123456789",
    image: "someBinaryData"
})
  • поиск аккаунта для входа в систему
db.client.find({
    email: "[email protected]",
    password: "password"
})
  • поиск предстоящих заказов для определенного клиента
db.order.find({
    "client.name": "Иван",
    "client.surname": "Иванов",
    endLeasing: { $gt: new Date() }
})
  • просмотр всех инструментов
db.tool.find({})
  • создание нового заказа
db.order.insert({
    _id: ObjectId(),
    tools: [
        { toolName: "Дрель", toolNumber: ObjectId("60725a34e8b57c4b3c2d9f12") },
        { toolName: "Перфоратор", toolNumber: ObjectId("60725a34e8b57c4b3c2d9f13") }
    ],
    startLeasing: new Date(),
    endLeasing: new Date(new Date().getTime() + 3 * 24 * 60 * 60 * 1000),
    price: 100,
    client: {
        name: "Иван",
        surname: "Иванов",
        phone: "1234567890"
    },
    deliveryType: "courier",
    deliveryState: "pending",
    paymentType: "credit card",
    paymentState: "unpaid",
    createOrderTime: new Date(),
    relatedWorker: {
        name: "Анна",
        surname: "Сидорова",
        phone: "0987654321"
    }
})
  • Вычисление и обновление рейтингов инструмента
db.tool.find().forEach(function(tool) {
    var totalRating = 0;
    var reviewCount = 0;

    db.review.find({ toolId: tool._id }).forEach(function(review) {
        totalRating += review.rating;
        reviewCount++;
    });

    if (reviewCount > 0) {
        var newRating = totalRating / reviewCount;
        db.tool.update(
            { _id: tool._id },
            { $set: { rating: newRating } }
        );
    }
});
  • Поиск всех инструментов, которые еще не вернули
db.order.find({
    endLeasing: { $gt: new Date() }
}).forEach(function(order) {
    order.tools.forEach(function(tool) {
        printjson(tool);
    });
});
  • поиск самых популярных инструментов
db.tool.aggregate([
    { $sort: { ordersNumber: -1 } },
    { $limit: 10 } // 10 самых популярных инструментов
]).forEach(function(tool) {
    printjson(tool);
});

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

Графическое представление

sql схема

Описание назначений коллекций, типов данных и сущностей

Разница от нереляционной версии:

  • наличие отдельной таблицы feature для хранения характеристик инструментов
  • наличие таблицы order_tool для реализации связи между таблицами order и tool

Поля и типы данных полей идентичны.

Оценка объема информации, хранимой в модели



Таблица client

Пусть x - количество клиентов, тогда:

$$ V(x) = x*(8+15+15+30+12+12+500000+8+8) = 500108x $$

  • _id - INT V = 8 байт
  • name - VARCHAR V = 15 байт
  • surname - VARCHAR V = 15 байт
  • email - VARCHAR V = 30 байт
  • password - VARCHAR V = 12 байт
  • contact - VARCHAR V = 12 байт
  • image - BinaryData V = 500000 байт
  • createdAt - Date V = 8 байт
  • editedAt - Date V = 8 байт


Таблица order

Пусть у каждого клиента будет 2 заказа. Тогда

$$ V(x) = 2x(8+8+...) = 184x $$

  • _id - INT V = 8 байт
  • startLeasing - Date V = 8 байт
  • endLeasing - Date V = 8 байт
  • price - Double V = 8 байт
  • clientId - INT V = 8 байт
  • deliveryType - VARCHAR V = 12 байт
  • deliveryState - VARCHAR V = 12 байт
  • paymentType - VARCHAR V = 12 байт
  • paymentState - VARCHAR V = 12 байт
  • workerId - INT = V = 8 байт


Таблица order_tool

Пусть в каждом заказе будет 3 инструмента. Так как у каждого клиента по 2 заказа, то

$$ V(x) = 2316*x = 96x $$

  • orderId - INT = 8 байт
  • toolId - INT = 8 байт


Таблица tool

Пусть у каждого инструмента есть 3 характеристики, 5 картинок и 50 отзывов, а всего существует 100 инструментов. Тогда: $$ V(x) = 100*(8+8+250000+8+12+12+8+8+12) = 25007600 $$

  • _id - INT V = 8 байт
  • dailyPrice - Double V = 8 байт
  • images - Array (предположим, что средний размер изображения составляет 50 Кб) V = 5*50000 = 250000 байт
  • rating - Double V = 8 байт
  • category - VARCHAR V = 12 байт
  • type - VARCHAR V = 12 байт
  • createdAt - Date V = 8 байт
  • totalPrice - Double V = 8 байт
  • condition - String V = 12 байт


Таблица worker

Пусть на каждого работника приходится 10 клиентов. Тогда:

$$ (x/10 + 1)*(12 + 15 + 15 + 15 + 15 + 15 + 15 + 8 + 240 + 8 + 8) = 10x + 100 $$

  • _id - INT V = 8 байт
  • name - VARCHAR V = 12 байт
  • surname - VARCHAR V = 12 байт
  • email - VARCHAR V = 12 байт
  • phone - VARCHAR V = 12 байт
  • jobTitle - VARCHAR V = 12 байт
  • state - VARCHAR V = 12 байт
  • date - Date V = 8 байт
  • createdAt - Date V = 8 байт
  • editedAt - Date V = 8 байт


Таблица feature

$$ V(x) = 100*3(8+8+12) = 8400 $$

  • _id - INT V = 8 байт
  • toolId - INT V = 8 байт
  • text - VARCHAR V = 12 байт


Таблица review

$$ V(x) = 100*50(8+8+8+12+8+8) = 260000 $$

  • _id - INT V = 8 байт
  • toolId - INT V = 8 байт
  • reviewerId - INT V = 8 байт
  • text - VARCHAR V = 12 байт
  • rating - INT V = 8 байт
  • date - Date V = 8 байт

Тогда получаем общий объём: $$ V(x) = 10x + 96x + 184x + 500108x + 8400 + 260000 + 25004800 + 90 = 500398x + 25273290 $$

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

В БД у клиентов может не быть картинки (пусть в среднем у 1 из 2 клиентов будет картинка, тогда средний размер будет равен половине от изначального). Тогда получаем:

$$ V(x) = 250199x + 289x + 250090600 = 250388x + 250090250 $$

Отношение между фактическим и "чистым" объемом (отбросив свободный член) равно

$$ \frac{500398x}{250388x} = 1.9 $$

Направление роста модели при увеличении количества объектов каждой сущности

Объём имеет линейный рост в зависимости от количества клиентов.

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

Таблица client

_id name surname email password contact image
1 Артём Палец [email protected] pass123 123-456-7890 [binary data]
2 Иван Смелый [email protected] pass456 987-654-3210 [binary data]

Таблица order

_id startLeasing endLeasing price clientId deliveryType deliveryState paymentType paymentState workerId
1 2023-01-01 2023-01-10 100.0 1 Standard Delivered CreditCard Paid 1
2 2023-02-01 2023-02-10 150.0 2 Express InProgress PayPal Pending 2

Таблица order_tool

orderId toolId
1 1
1 2
1 3
2 1
2 2
2 4

Таблица tool

_id dailyPrice images rating category type
1 10.0 [binary data] 4.5 Drill Electric
2 15.0 [binary data] 4.0 Saw Manual

Таблица worker

_id name surname email phone jobTitle state date
1 Алиса Иванова [email protected] 555-123-4567 Manager Active 2023-01-01
2 Олег Иванов [email protected] 555-987-6543 Worker Active 2023-02-01

Таблица feature

_id toolId text
1 1 High power
2 1 Lightweight
3 2 Durable

Таблица review

_id toolId reviewerId text rating date
1 1 1 Great tool! 5 2023-01-02
2 1 2 Works well. 4 2023-01-03
3 2 1 Good for the price. 3 2023-01-04

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

  • регистрация нового клиента
INSERT INTO client (_id, name, surname, email, password, phone, image)
VALUES (NULL, 'Иван', 'Иванов', '[email protected]', 'password', '+79123456789', 'someBinaryData');
  • поиск аккаунта для входа в систему
SELECT * FROM client
WHERE email = '[email protected]' AND password = 'password';
  • поиск предстоящих заказов для определенного клиента
SELECT * FROM orders
WHERE clientId = (SELECT _id FROM client WHERE name = 'Иван' AND surname = 'Иванов')
AND endLeasing > CURRENT_DATE;

  • просмотр всех инструментов
SELECT * FROM tool;

  • создание нового заказа
INSERT INTO orders (_id, startLeasing, endLeasing, price, clientId, deliveryType, deliveryState, paymentType, paymentState, createOrderTime, relatedWorkerId)
VALUES (NULL, CURRENT_DATE, DATE_ADD(CURRENT_DATE, INTERVAL 3 DAY), 100, (SELECT _id FROM client WHERE name = 'Иван' AND surname = 'Иванов'), 'courier', 'pending', 'credit card', 'unpaid', CURRENT_DATE, (SELECT _id FROM worker WHERE name = 'Анна' AND surname = 'Сидорова'));

INSERT INTO order_tool (orderId, toolId)
VALUES (LAST_INSERT_ID(), GET_TOOL_ID('Дрель'));

INSERT INTO order_tool (orderId, toolId)
VALUES (LAST_INSERT_ID(), GET_TOOL_ID('Перфоратор'));

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

  • NoSQL требует больше памяти, по сравнению с SQL, так в нем дублируются некоторые данные. SQL выигрывает по памяти, так как вместо того, чтобы хранить сами объекты целиком (как NoSQL), он хранит только id определенного элемента из другой таблицы.
  • По удобству запросов выигрывает NoSQL, так как ввиду дублирования данных в некоторых сущностях, нам не приходится JOIN-ить с другими коллекциями. Для некоторых запросов SQL приходится JOIN-ить несколько таблиц, что может сказать в скорости доступа.

Вывод

NoSQL требует больше памяти, но удобен и быстр в запросах, в то время как SQL требует меньше памяти и не совсем удобен в запросах, из-за того что приходится JOIN-ить таблицы. Для данной задачи NoSQL подходит лучше, чем SQL.

Clone this wiki locally