\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}