-
Notifications
You must be signed in to change notification settings - Fork 0
Модель данных
Далее используемые обозначения для расчета среднего объёма
-
$N_{players} = 15$ - количество игроков в одной команде без организатора игры $L_{name} = 20$ $L_{address} = 60$ $L_{pass} = 20$ $L_{email}= 40$ $L_{wishlist} = 200$ $L_{stoplist} = 100$ -
$N_{games}$ - количество команд, переменная
БД содержит 3 коллекции - "Game", "User", "Event":
-
Коллекция "Game"
- id - идентификатор каждой команды/игры в Тайного Санту. 8 байт
- lowest_price - нижняя граница стоимости подарка. 8 байт
- highest_price - верхняя граница стоимости подарка. 8 байт
- form_deadline - срок, к которому нужно заполнить анкету. 8 байт
- purchase_deadline - срок, к которому нужно купить подарок. 8 байт
- send_deadline - срок, к которому нужно отправить подарок. 8 байт
- created_at - дата создания. 8 байт
- updated_at - дата обновления. 8 байт
- users - игроки данной команды, в том числе и организатор.
$N_{players}*V_{user} + V_{host} + N_{players}*8 = 7480 +$ - events - события, относящиеся к этой игре (заполнение анкеты, покупка подарка и т.д.). Верхняя граница(произошли все события для каждого игрока):
$5N_{players}*V_{event}= 1300$ байт
$V_{game} = 8844$ байт -
Коллекция "User"
- id - пользователь. 8 байт
- password - пароль.
$L_{pass} * 1 = 20$ байт - email - электронная почта.
$L_{email} * 1 = 20$ байт - is_host - является ли организатором. 1 байт
- name - имя.
$L_{name} * 1 = 20$ байт - address - адрес.
$L_{address} * 1 = 60$ байт - index - индекс. 4 байта
- phone - телефон. 8 байт
- status - статус игрока(ничего не сделал/ заполнил анкету/ купил подарок/ отправил его). 4 байта (none, form, paid, sent)
- delivery_type - способ доставки подарка. 6 байт (mail, other, ticket, cert, none)
- wishlist - желания игрока.
$L_{wishlist} * 1 = 200$ байт - stoplist - "стоплист".
$L_{stoplist} * 1 = 100$ байт - recipient - идентификатор получателя. 8 байт
- santa - идентификатор того, кто будет "Тайным Сантой" данного игрока. 8 байт
- got_gift - получил ли пользователь подарок. 1 байт
- wrong_gift - купил ли игрок подарок, пересекающийся со стоплистом. 1 байт
- created_at - дата создания. 8 байт
- updated_at - дата обновления. 8 байт
$V_{user} = 485$ байтаЧастный случай пользователя организатора -
$V_{host} = V_{id} + V_{pass} + V_{email} + V_{name} + V_{ishost} + V_{createdat} + V_{updatedat} = 85$ байт -
Коллекция "Event"
- player_id - идентификатор игрока, совершившего определенноё действие 8 байт
- type - тип события 4 байта
- date - дата 8 байт
$V_{event} = 20$ байт
Дублирующиеся поля - player_id в коллекции Event, recipient, santa в коллекции User - идентификаторы участвующих игроков.
Также дублируется поле player_id в коллекции Game
Объём без дублирования информации - 7964
Избыточность модели =
- Новая запись об игре влечет за собой новую запись о пользователе-организаторе
- Каждая новая запись об игроке - потенциальные новые записи в коллекции Event
- Новые документы в таблице Event ни на что не влияют
- Game
{'_id': ObjectId('6722d278ee5e086effffc8b0'),
'id': 1,
'lowest_price': 1000,
'highest_price': 2000,
'form_deadline': datetime.datetime(2024, 11, 18, 0, 0),
'purchase_deadline': datetime.datetime(2024, 12, 11, 0, 0),
'send_deadline': datetime.datetime(2024, 12, 21, 0, 0),
'users': [1, 2],
'events': [
{
'player_id': 2,
'type': 2,
'date': datetime.datetime(2024, 11, 21, 0, 0)
}
],
'created_at': datetime.datetime(2024, 11, 11, 0, 0),
'updated_at': datetime.datetime(2024, 11, 12, 0, 0)
}
- User
{
'_id': ObjectId('6722d278ee5e086ddmeff8b0'),
'id': 1,
'name': 'test_user1',
'email': '[email protected]',
'password': 'aafewfwefg',
'is_host': True,
'created_at': datetime.datetime(2024, 11, 11, 0, 0),
'updated_at': datetime.datetime(2024, 11, 12, 0, 0)
},
{
'_id': ObjectId('6722d278ee5e086effffuyuggb0'),
'id': 2,
'name': 'test_user2',
'email': '[email protected]',
'password': 'hnhytresfsd',
'is_host': False,
'address': 'nevsky str. 17',
'index': 111111,
'phone': 89999999999,
'status' : 1,
'delivery_type': 1,
'wishlist': 'flowers',
'stoplist': 'candles',
'recipient' : 2 ,
'santa': 3,
'got_gift': False,
'created_at': datetime.datetime(2024, 11, 11, 0, 0),
'updated_at': datetime.datetime(2024, 11, 12, 0, 0),
'wrong_gift': False,
}
- Event
{
'player_id': 2,
'type': 2,
'date': datetime.datetime(2024, 11, 21, 0, 0)
}
- Запрос на отображение списка желаний пользователя по id
users.find_one({'id':'1'}).get('wishlist')
- Запрос на обновление анкеты
users.update_one({'id':1}, {
'$set':
{
'wishlist':"flowers",
'stoplist':"candles",
'phone': 8999999999999,
'index': 111111,
'address':"nevsky str.1"
}
})
- Запрос на отображение участников конкретной игры
for player_id in games.find_one({'id':1}).get('users'):
print(users.find_one({'id': player_id }))
- Запрос на отображение участников, чью покупку админ посчитал пересекающейся со стоплистом
game_column = db["games"]
player_column = db["users"]
wrong = []
for game in game_column.find():
for player in player_column.find({ "id": { "$in": game["players"]}}):
if player["wrong_gift"]:
wrong.append(player)
- Запрос на отображение всех игр, где есть участники, просрочившие дедлайн покупки подарка
game_column = db["games"]
player_column = db["users"]
expired = []
current_date = dateutil.utils.today()
enum = ["none", "form", "paid", "sent"]
for game in game_column.find():
if game["form_deadline"] < current_date:
for player in player_column.find({ "id": { "$in": game["players"]}}):
if not player["is_host"] and enum.index(player["status"]) < 2:
expired.append(game)
break
- Запрос на отображение участников конкретной игры, ещё не купивших подарок
game = db["games"].find_one({ "id": { "$in": [game_id]}})
player_column = db["users"]
late = []
enum = ["none", "form", "paid", "sent"]
for player in player_column.find({ "id": { "$in": game["players"]}}):
if not player["is_host"] and enum.index(player["status"]) < 2:
late.append(player)
БД содержит 4 отношения - "Game", "Host", "Player", "Event":
-
Отношение "Game"
- id - идентификатор каждой команды/игры в Тайного Санту. Ключ 8 байт
- lowest_price - нижняя граница стоимости подарка 8 байт
- highest_price - верхняя граница стоимости подарка 8 байт
- form_deadline - срок, к которому нужно заполнить анкету 8 байт
- purchase_deadline - срок, к которому нужно купить подарок 8 байт
- send_deadline - срок, к которому нужно отправить подарок 8 байт
- created_at - дата создания. 8 байт
- updated_at - дата обновления. 8 байт
$V_{game} = 64$ байт -
Отношение "Host"
- id - идентификатор организатора. Ключ 8 байт
- password - пароль
$L_{pass} * 1 = 20$ байт - email - электронная почта
$L_{email} * 1 = 40$ байт - game_id - идентификатор игры, в которой данный пользователь является организатором 8 байт
- name - имя
$L_{name} * 1 = 20$ байт - created_at - дата создания. 8 байт
- updated_at - дата обновления. 8 байт
$V_{host} = 112$ байт -
Отношение "Player"
- id - идентификатор игрока. Ключ 8 байт
- password - пароль $L_{pass} * 1 = 20 $ байт
- email - электронная почта
$L_{email} * 1 = 40$ байт - game_id - идентификатор команды, в которой находится пользователь 8 байт
- name - имя
$L_{name} * 1 = 20$ байт - wishlist - желания игрока
$L_{wishlist} * 1 = 200$ байт - stoplist - "стоплист"
$L_{stoplist} * 1 = 100$ байт - address - адрес
$L_{address} * 1 = 60$ байт - index - индекс 4 байта
- phone - телефон 8 байт
- got_gift - получил ли пользователь подарок 1 байт
- status - статус игрока(ничего не сделал/ заполнил анкету/ купил подарок/ отправил его) 1 байт
- delivery_type - способ доставки подарка 1 байт
- recipient - идентификатор получателя 8 байт
- santa - идентификатор игрока, который будет "Тайным Сантой"данного игрока 8 байт
- wrong_gift - купил ли игрок подарок, пересекающийся со стоплистом 1 байт
- created_at - дата создания. 8 байт
- updated_at - дата обновления. 8 байт
-
Отношение "Event"
- game_id - идентификатор игры, к которой относится данное событие. 8 байт
- player_id - идентификатор игрока, совершившего определенноё действие. 8 байт
- type - тип события. game_id + player_id + type - ключ данной таблицы 4 байт
- date - дата 8 байт
$V_{event} = 28$ байт
Дублирующиеся поля:
- player_id в отношении Event, recipient, santa в отношении Player - идентификаторы участвующих игроков.
- game_id в отношении Event, game_id в отношениях Player, Host - идентификаторы игры.
Объём без дублирования информации - 8148 байт.
Избыточность модели =$\frac{9556}{8148} = 1.17 $
- При создании записи для команды будет создаваться запись для организатора игры
- Аналогично ввод нового игрока приведёт к новым возможным событиям
- Запись событий не приведет к росту других записей
- Отношение Game
id | lowest_price | highest_price | form_deadline | purchase_deadline | send_deadline | created_at | updated_at |
---|---|---|---|---|---|---|---|
1 | 1000 | 2000 | 18.11.2024 | 30.11.2024 | 12.12.2024 | 2024-11-08 23:59:59 | 2024-11-09 23:59:59 |
- Отношение Host
id | password | game_id | name | created_at | updated_at | |
---|---|---|---|---|---|---|
1 | fiuuhfie | [email protected] | 1 | Ivan | 2024-11-08 23:59:59 | 2024-11-09 23:59:59 |
- Отношение Player
id | password | game_id | name | wishlist | stoplist | address | index | phone | got_gift | status | delivery_type | recipient | santa | wrong_gift | created_at | updated_at | |
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
1 | fiuuhfe | [email protected] | 1 | Ivan | flowers | candles | Nevsky str. 17 | 1111 | 89999999999 | false | form | none | 2 | 3 | false | 2024-11-08 23:59:59 | 2024-11-09 23:59:59 |
2 | uuhfe | [email protected] | 1 | Katya | books | candies | Professora Popova str. 16 | 1111 | 89129999999 | false | none | none | 3 | 1 | false | 2024-11-08 23:59:59 | 2024-11-09 23:59:59 |
3 | udlfwefwefwhfe | [email protected] | 1 | Mary | perfume and sweets | stationery | Nevsky str. 16 | 1111 | 89999999999 | true | none | none | 1 | 3 | false | 2024-11-08 23:59:59 | 2024-11-09 23:59:59 |
- Отношение Event
game_id | player_id | type | date |
---|---|---|---|
1 | 1 | form | 17.11.2024 |
1 | 3 | form | 10.11.2024 |
1 | 3 | purchase | 14.11.2024 |
- Запрос на отображение списка желаний пользователя по id
SELECT wishlist
FROM players
WHERE id=1
- Запрос на обновление анкеты
UPDATE users
SET wishlist = "flowers", stoplist = "sweets",phone=8999999999999, index=111111, address="nevsky str.1"
WHERE id = 1
- Запрос на отображение участников конкретной игры
SELECT *
FROM players
WHERE game_id=1
- Запрос на отображение участников, чью покупку админ посчитал пересекающейся со стоплистом
SELECT player_id FROM player
WHERE wrong_gift = TRUE;
- Запрос на отображение всех игр, где есть участники, просрочившие дедлайн покупки подарка
SELECT game.game_id
FROM game
INNER JOIN player
ON game.game_id = player.game_id
WHERE status < 'bought' AND purchase_deadline < NOW()
GROUP BY game.game_id;
- Запрос на отображение участников конкретной игры, ещё не купивших подарок
FROM player
INNER JOIN game
ON game.game_id = player.game_id
WHERE game.game_id = 2 AND status < 'bought' AND purchase_deadline < NOW()
GROUP BY player.player_id;
Объём, зависящий от количества зарегистрированных команд в нереляционной БД немного меньше, чем в реляционной -
1.11 в нереляционной и 1.17 в реляционной
Юзкейс | NoSQL | SQL |
---|---|---|
1 | Количество запросов:2, используемых коллекций:2 | Количество запросов:3, используемых отношений:3 |
2 | Количество запросов:1, используемых коллекций:1 | Количество запросов:2, используемых отношений:2 |
3 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
4 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
6 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
7 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
8 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
9 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
11 | Количество запросов:3, используемых коллекций:3 | Количество запросов:4, используемых отношений:4 |
12 | Количество запросов:3, используемых коллекций:3 | Количество запросов:4, используемых отношений:4 |
14 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
15 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
16 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
17 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
18 | Количество запросов:1, используемых коллекций:1 | Количество запросов:1, используемых отношений:1 |
Благодаря меньшему объёму, количеству коллекций, чуть меньшему количеству запросов и примерно той же избыточности, производительности, количеству запросов, в данном проекте немного предпочтительнее использовать нереляционную БД. Но, тем не менее, писать запросы со сложной фильтрацией намного легче именно в реляционной БД.