Mikołaj Kaczmarek b44bba0a50
1.1
2025-06-29 11:58:11 +02:00

572 lines
16 KiB
TeX

\documentclass{article}
\usepackage{fontspec}
\usepackage{polyglossia}
\usepackage{geometry}
\usepackage{graphicx}
\usepackage{minted}
\usepackage{xcolor}
\usepackage{hyperref}
\usepackage{tabularx}
\usepackage{enumitem}
% Ustawienia języka polskiego
\setmainlanguage{polish}
\setotherlanguage{english}
\setlength{\parindent}{0pt}
\renewcommand{\baselinestretch}{1.2}
\geometry{a4paper, margin=2.5cm}
% Ustawienia dla pakietu minted
\usemintedstyle{vs}
\setminted{
fontsize=\normalsize,
breaklines=true,
breakanywhere=true,
frame=single,
framesep=2mm,
linenos=true,
tabsize=2
}
\begin{document}
\begin{center}
{\LARGE \textbf{ZTBD - sprawozdanie z projektu}}
\\[1.5em]
{\large 2025-05-24}\\[2em]
\end{center}
\section*{Podstawowe informacje}
\begin{tabular}{ll}
\textbf{Autorzy projektu:} & Mikołaj Kaczmarek (124942) \\
& Piotr Wilma (124832) \\
\textbf{Temat:} & Hotel \\
\textbf{Wybrany zakres (ocena):} & 5,0 \\
\textbf{Baza danych:} & \texttt{ztbd124942} \\
\end{tabular}
\section{Wprowadzenie}
Projekt obejmuje stworzenie bazy danych MongoDB dla hotelu.
System zarządzania hotelem wymaga przechowywania danych o gościach, pokojach, rezerwacjach, pracownikach oraz usługach dodatkowych.
Opracowana baza danych umożliwia śledzenie aktualnego stanu rezerwacji, zarządzanie dostępnością pokoi oraz realizację dodatkowych zamówień gości hotelowych.
Rozwiązanie takie znajduje zastosowanie w każdym obiekcie hotelowym potrzebującym wszechstronnego systemu do zarządzania codzienną działalnością.
Główne funkcjonalności realizowane przez bazę danych obejmują:
\begin{itemize}
\item Przechowywanie informacji o gościach wraz z ich danymi kontaktowymi
\item Zarządzanie pokojami hotelowymi i ich atrybutami
\item Obsługę rezerwacji z informacją o terminach pobytu i statusie płatności
\item Ewidencję pracowników hotelu z przypisaniem do działów
\item Katalog usług dodatkowych oraz zamówień na te usługi
\end{itemize}
\section{Schemat bazy - kolekcje}
Opracowana baza danych składa się z 6 kolekcji, łącznie zawierających 70 dokumentów.
Poniżej przedstawiono szczegółowy opis każdej kolekcji wraz z przykładowymi dokumentami.
\subsection{Kolekcja: guests}
\textbf{Opis:} Przechowuje dane gości hotelowych wraz z informacjami kontaktowymi i dodatkowymi atrybutami.
\textbf{Liczba dokumentów:} 15
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
firstName: String,
lastName: String,
email: String,
phoneNumber: String,
address: {
street: String,
city: String,
postalCode: String,
country: String
},
dateOfBirth: Date,
loyaltyPoints: Number,
registrationDate: Date
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
firstName: "Jan",
lastName: "Kowalski",
email: "jan.kowalski@email.com",
phoneNumber: "+48123456789",
address: {
street: "Kwiatowa 12",
city: "Warszawa",
postalCode: "01-234",
country: "Polska"
},
dateOfBirth: ISODate("1985-05-15T00:00:00Z"),
loyaltyPoints: 120,
registrationDate: ISODate("2020-03-10T00:00:00Z")
}
\end{minted}
\subsection{Kolekcja: rooms}
\textbf{Opis:} Zawiera informacje o pokojach hotelowych, ich typach, wyposażeniu i statusie dostępności.
\textbf{Liczba dokumentów:} 12
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
roomNumber: String,
floor: Number,
type: String,
capacity: Number,
pricePerNight: Number,
amenities: [String],
status: String,
lastRenovation: Date
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
roomNumber: "301",
floor: 3,
type: "Suite",
capacity: 4,
pricePerNight: 600.00,
amenities: ["TV", "WiFi", "Minibar", "Klimatyzacja",
"Sejf", "Ekspres do kawy", "Jacuzzi"],
status: "Dostępny",
lastRenovation: ISODate("2022-02-15T00:00:00Z")
}
\end{minted}
\subsection{Kolekcja: reservations}
\textbf{Opis:} Przechowuje informacje o rezerwacjach gości, zawiera referencje do kolekcji guests i rooms.
\textbf{Liczba dokumentów:} 10
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
guestId: ObjectId("..."),
roomId: ObjectId("..."),
checkInDate: Date,
checkOutDate: Date,
numberOfGuests: Number,
totalPrice: Number,
paymentStatus: String,
specialRequests: [String],
bookingDate: Date,
status: String
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
guestId: ObjectId("..."),
roomId: ObjectId("..."),
checkInDate: ISODate("2023-05-10T00:00:00Z"),
checkOutDate: ISODate("2023-05-15T00:00:00Z"),
numberOfGuests: 2,
totalPrice: 1250.00,
paymentStatus: "Opłacone",
specialRequests: ["Późne zameldowanie", "Dodatkowa poduszka"],
bookingDate: ISODate("2023-04-15T00:00:00Z"),
status: "Potwierdzona"
}
\end{minted}
\subsection{Kolekcja: employees}
\textbf{Opis:} Zawiera dane pracowników hotelu wraz z informacjami o stanowisku, wynagrodzeniu i harmonogramie pracy.
\textbf{Liczba dokumentów:} 8
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
firstName: String,
lastName: String,
position: String,
email: String,
phoneNumber: String,
dateOfBirth: Date,
hireDate: Date,
salary: Number,
department: String,
workSchedule: [String],
address: {
street: String,
city: String,
postalCode: String,
country: String
}
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
firstName: "Tomasz",
lastName: "Nowicki",
position: "Szef kuchni",
email: "tomasz.nowicki@hotel.com",
phoneNumber: "+48567890123",
dateOfBirth: ISODate("1975-03-10T00:00:00Z"),
hireDate: ISODate("2018-06-01T00:00:00Z"),
salary: 7500.00,
department: "Restauracja",
workSchedule: ["Poniedziałek", "Wtorek", "Środa", "Niedziela"],
address: {
street: "Słoneczna 8",
city: "Pruszków",
postalCode: "05-800",
country: "Polska"
}
}
\end{minted}
\subsection{Kolekcja: services}
\textbf{Opis:} Zawiera katalog usług dodatkowych oferowanych przez hotel.
\textbf{Liczba dokumentów:} 10
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
name: String,
description: String,
price: Number,
category: String,
availability: [String],
location: String,
requiresReservation: Boolean
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
name: "Masaż relaksacyjny",
description: "60-minutowy masaż relaksacyjny",
price: 200.00,
category: "SPA",
availability: ["Poniedziałek", "Środa", "Piątek", "Sobota"],
location: "Hotelowe SPA",
requiresReservation: true
}
\end{minted}
\subsection{Kolekcja: serviceOrders}
\textbf{Opis:} Przechowuje zamówienia na usługi dodatkowe składane przez gości hotelowych.
\textbf{Liczba dokumentów:} 15
\textbf{Struktura dokumentu:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
guestId: ObjectId("..."),
reservationId: ObjectId("..."),
serviceId: ObjectId("..."),
orderDate: Date,
quantity: Number,
totalPrice: Number,
status: String,
comments: String
}
\end{minted}
\textbf{Przykładowy dokument:}
\begin{minted}{javascript}
{
_id: ObjectId("..."),
guestId: ObjectId("..."),
reservationId: ObjectId("..."),
serviceId: ObjectId("..."),
orderDate: ISODate("2023-06-18T00:00:00Z"),
quantity: 1,
totalPrice: 300.00,
status: "Potwierdzone",
comments: "Kolacja na 20:00, rocznica ślubu"
}
\end{minted}
\section{Referencje między dokumentami}
W bazie danych zaimplementowano następujące referencje między dokumentami:
\begin{enumerate}
\item \textbf{Rezerwacje (reservations) - Goście (guests)}
\begin{itemize}
\item Atrybut \texttt{guestId} w kolekcji \texttt{reservations} zawiera referencję do identyfikatora dokumentu z kolekcji \texttt{guests}
\item Modeluje relację: "Gość dokonuje rezerwacji" (jeden gość może mieć wiele rezerwacji)
\end{itemize}
\item \textbf{Rezerwacje (reservations) - Pokoje (rooms)}
\begin{itemize}
\item Atrybut \texttt{roomId} w kolekcji \texttt{reservations} zawiera referencję do identyfikatora dokumentu z kolekcji \texttt{rooms}
\item Modeluje relację: "Rezerwacja dotyczy konkretnego pokoju" (jeden pokój może mieć wiele rezerwacji w różnych terminach)
\end{itemize}
\item \textbf{Zamówienia usług (serviceOrders) - Goście (guests)}
\begin{itemize}
\item Atrybut \texttt{guestId} w kolekcji \texttt{serviceOrders} zawiera referencję do identyfikatora dokumentu z kolekcji \texttt{guests}
\item Modeluje relację: "Gość zamawia usługę dodatkową" (jeden gość może złożyć wiele zamówień)
\end{itemize}
\item \textbf{Zamówienia usług (serviceOrders) - Rezerwacje (reservations)}
\begin{itemize}
\item Atrybut \texttt{reservationId} w kolekcji \texttt{serviceOrders} zawiera referencję do identyfikatora dokumentu z kolekcji \texttt{reservations}
\item Modeluje relację: "Zamówienie usługi jest przypisane do konkretnej rezerwacji" (jedna rezerwacja może mieć wiele zamówień usług)
\end{itemize}
\item \textbf{Zamówienia usług (serviceOrders) - Usługi (services)}
\begin{itemize}
\item Atrybut \texttt{serviceId} w kolekcji \texttt{serviceOrders} zawiera referencję do identyfikatora dokumentu z kolekcji \texttt{services}
\item Modeluje relację: "Zamówienie dotyczy konkretnej usługi" (jedna usługa może być zamawiana wielokrotnie)
\end{itemize}
\end{enumerate}
\section{Zapytania}
\subsection{Zapytania wyszukujące (find)}
\subsubsection{Dostępne pokoje o pojemności większej niż 2 osoby}
\begin{minted}{javascript}
// Zapytanie wyszukujące dostępne pokoje o pojemności większej niż 2 osoby
db.rooms.find(
{
status: "Dostępny",
capacity: { $gt: 2 }
}
)
\end{minted}
Zapytanie zwraca wszystkie pokoje, które są obecnie dostępne i mogą pomieścić więcej niż 2 osoby.
Wykorzystuje operator porównujący \texttt{\$gt} (greater than).
\subsubsection{Rezerwacje rozpoczynające się w określonym przedziale czasowym}
\begin{minted}{javascript}
// Zapytanie wyszukujące rezerwacje z zameldowaniem w czerwcu 2023
db.reservations.find(
{
checkInDate: {
$gte: new Date("2023-06-01"),
$lt: new Date("2023-07-01")
}
}
)
\end{minted}
Zapytanie zwraca wszystkie rezerwacje z datą zameldowania w czerwcu 2023.
Wykorzystuje operatory porównujące \texttt{\$gte} (greater than or equal) i \texttt{\$lt} (less than).
\subsection{Zapytania grupujące (aggregate)}
\subsubsection{Średnia cena i liczba rezerwacji według typu pokoju}
\begin{minted}{javascript}
// Zapytanie grupujące - statystyki rezerwacji wg typu pokoju
db.reservations.aggregate([
{
$lookup: {
from: "rooms",
localField: "roomId",
foreignField: "_id",
as: "room"
}
},
{
$unwind: "$room"
},
{
$group: {
_id: "$room.type",
averagePrice: { $avg: "$totalPrice" },
totalReservations: { $sum: 1 },
totalRevenue: { $sum: "$totalPrice" }
}
},
{
$sort: {
totalRevenue: -1
}
},
{
$project: {
roomType: "$_id",
averagePrice: { $round: ["$averagePrice", 2] },
totalReservations: 1,
totalRevenue: 1,
_id: 0
}
}
])
\end{minted}
Zapytanie łączy dane z kolekcji rezerwacji i pokoi, a następnie grupuje je według typu pokoju.
Dla każdego typu pokoju obliczane są: średnia cena rezerwacji, liczba rezerwacji i całkowity przychód.
Wyniki są sortowane według przychodu malejąco.
Wykorzystane operatory to \texttt{\$group}, \texttt{\$lookup}, \texttt{\$sort} i \texttt{\$project}.
\subsubsection{Analiza zamówień usług dodatkowych według kategorii}
\begin{minted}{javascript}
// Zapytanie grupujące - analiza zamówień usług wg kategorii
db.serviceOrders.aggregate([
{
$lookup: {
from: "services",
localField: "serviceId",
foreignField: "_id",
as: "serviceDetails"
}
},
{
$unwind: "$serviceDetails"
},
{
$match: {
status: { $in: ["Potwierdzone", "Zrealizowane"] }
}
},
{
$group: {
_id: "$serviceDetails.category",
totalOrders: { $sum: 1 },
totalRevenue: { $sum: "$totalPrice" },
averageQuantity: { $avg: "$quantity" }
}
},
{
$sort: {
totalOrders: -1
}
},
{
$limit: 5
},
{
$project: {
category: "$_id",
totalOrders: 1,
totalRevenue: { $round: ["$totalRevenue", 2] },
averageQuantity: { $round: ["$averageQuantity", 2] },
_id: 0
}
}
])
\end{minted}
Zapytanie analizuje zamówienia usług dodatkowych, łącząc dane z kolekcji zamówień i usług.
Filtruje zamówienia o statusie "Potwierdzone" lub "Zrealizowane", grupuje je według kategorii usługi i oblicza statystyki: liczbę zamówień, całkowity przychód i średnią ilość zamówionych usług.
Wyniki są sortowane według liczby zamówień i ograniczone do 5 najlepszych kategorii.
Wykorzystane operatory to \texttt{\$lookup}, \texttt{\$match}, \texttt{\$group}, \texttt{\$sort}, \texttt{\$limit} i \texttt{\$project}.
\subsection{Zapytanie zliczające (count)}
\begin{minted}{javascript}
// Zapytanie zliczające pokoje wg statusu dostępności
db.rooms.countDocuments(
{
status: "Dostępny",
pricePerNight: { $lt: 500 }
}
)
\end{minted}
Zapytanie zwraca liczbę pokoi, które są obecnie dostępne i kosztują mniej niż 500 zł za noc.
Wykorzystuje metodę \texttt{countDocuments} z parametrem query.
\subsection{Zapytanie o wartości unikalne (distinct)}
\begin{minted}{javascript}
// Zapytanie o unikalne kraje pochodzenia gości
db.guests.distinct(
"address.country",
{
loyaltyPoints: { $gt: 50 }
}
)
\end{minted}
Zapytanie zwraca listę unikalnych krajów pochodzenia gości, którzy posiadają więcej niż 50 punktów lojalnościowych.
Wykorzystuje metodę \texttt{distinct} z parametrem query.
\section{Indeksy}
W celu optymalizacji zapytań w bazie danych utworzono następujące indeksy:
\begin{minted}{javascript}
// Indeks dla szybkiego wyszukiwania pokoi po numerze
db.rooms.createIndex({ roomNumber: 1 }, { unique: true })
// Indeks dla szybkiego wyszukiwania gości po nazwisku i imieniu
db.guests.createIndex({ lastName: 1, firstName: 1 })
// Indeks dla szybkiego wyszukiwania rezerwacji wg dat
db.reservations.createIndex({ checkInDate: 1, checkOutDate: 1 })
// Indeks dla szybszego łączenia rezerwacji z pokojami
db.reservations.createIndex({ roomId: 1 })
// Indeks dla szybszego łączenia rezerwacji z gośćmi
db.reservations.createIndex({ guestId: 1 })
// Indeks dla szybkiego wyszukiwania usług wg kategorii i ceny
db.services.createIndex({ category: 1, price: 1 })
// Indeks dla szybszego łączenia zamówień usług z usługami
db.serviceOrders.createIndex({ serviceId: 1 })
// Indeks dla szybszego łączenia pracowników z działami i stanowiskami
db.employees.createIndex({ department: 1, position: 1 });
\end{minted}
Indeksy przyspieszają operacje wyszukiwania i łączenia danych, szczególnie w przypadku złożonych zapytań agregujących.
Na przykład, indeks \texttt{roomNumber} zapewnia szybkie wyszukiwanie pokoju po jego numerze, a indeksy na polach \texttt{guestId} i \texttt{roomId} w kolekcji \texttt{reservations} przyspieszają operacje łączenia danych z różnych kolekcji.
\end{document}