{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "## Zoo-Verwaltung in MongoDB\n", "\n", "In diesem Beispiel soll die einfache Zoo-Verwaltung aus der Aufgabe zuvor in MongoDB umgesetzt werden. \n", "\n", "Installieren Sie dazu zunächst MongoDB auf Ihrem Rechner, hier finden Sie den Download und die Dokumentation zur Installation:\n", "https://www.mongodb.com/try/download/community\n", "\n", "Um MongoDB in Python zu verwenden, benötigen Sie das Modul `pymongo`. Installieren Sie es mit dem folgenden Befehl:\n", "\n", " conda install conda-forge::pymongo\n", "\n" ] }, { "cell_type": "code", "metadata": { "ExecuteTime": { "end_time": "2026-05-08T09:19:56.611402767Z", "start_time": "2026-05-08T09:19:56.593625065Z" } }, "source": [ "# Client importieren\n", "from pymongo import MongoClient" ], "outputs": [], "execution_count": 38 }, { "cell_type": "code", "metadata": { "ExecuteTime": { "end_time": "2026-05-08T09:19:59.004412525Z", "start_time": "2026-05-08T09:19:58.962687290Z" } }, "source": [ "# Verbindungsaufbau zu einer MongoDB-Datenbank\n", "client = MongoClient('localhost', 27017)\n", "\n", "# Zoo-Datenbank erstellen\n", "db = client['zoo']\n", "\n", "# Beispiel-Dokument in Collection 'animals' erstellen\n", "db.animals.insert_one({'name': 'Ella', 'species': 'elephant'})\n", "\n", "# Alle Dokumente in Collection 'animals' ausgeben\n", "for animal in db.animals.find():\n", " print(animal)" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "{'_id': ObjectId('69fda3a4eabd702ea246e9c7'), 'name': 'Babar', 'species': 'Elephant', 'zookeeper_id': ObjectId('69fda3a4eabd702ea246e9c5')}\n", "{'_id': ObjectId('69fda3a4eabd702ea246e9c8'), 'name': 'Dumbo', 'species': 'Elephant', 'zookeeper_id': ObjectId('69fda3a4eabd702ea246e9c5')}\n", "{'_id': ObjectId('69fda3a4eabd702ea246e9c9'), 'name': 'Gloria', 'species': 'Giraffe', 'zookeeper_id': ObjectId('69fda3a4eabd702ea246e9c6')}\n", "{'_id': ObjectId('69fdaabeeabd702ea246e9cb'), 'name': 'Ella', 'species': 'elephant'}\n" ] } ], "execution_count": 39 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Teilaufgabe 1 (4 Punkte): \n", "\n", "Fügen Sie im folgenden Dokumente ein, die die selben Informationen enthalten wie in der Aufgabe zuvor. Dabei sollen drei Tiere mit zwei Tierpfegern erstellt werden. Ein Tierpfleger versorgt mehrere Tiere, jedes Tier ist genau einem Tierpfleger zugeordnet. Ob Sie die Daten dabei normalisieren oder nicht, bleibt Ihnen überlassen." ] }, { "cell_type": "code", "metadata": { "ExecuteTime": { "end_time": "2026-05-08T09:20:04.598013716Z", "start_time": "2026-05-08T09:20:04.557642811Z" } }, "source": [ "# Aufräumen\n", "db.zookeepers.drop()\n", "db.animals.drop()\n", "\n", "# Tierpfleger hinzufügen\n", "john_id = db.zookeepers.insert_one(\n", " {\n", " \"name\": \"John Doe\",\n", " \"email\": \"john@example.com\",\n", " \"speciality\": \"Elephants\"\n", " }\n", ").inserted_id\n", "jane_id = db.zookeepers.insert_one(\n", " {\n", " \"name\": \"Jane Doe\",\n", " \"email\": \"jane@example.com\",\n", " \"speciality\": \"Giraffes\"\n", " }\n", ").inserted_id\n", "\n", "# Tiere hinzufügen\n", "db.animals.insert_many([\n", " {\n", " \"name\": \"Babar\",\n", " \"species\": \"Elephant\",\n", " \"zookeeper_id\": john_id\n", " },\n", " {\n", " \"name\": \"Dumbo\",\n", " \"species\": \"Elephant\",\n", " \"zookeeper_id\": john_id\n", " },\n", " {\n", " \"name\": \"Gloria\",\n", " \"species\": \"Giraffe\",\n", " \"zookeeper_id\": jane_id\n", " },\n", "])" ], "outputs": [ { "data": { "text/plain": [ "InsertManyResult([ObjectId('69fdaac4eabd702ea246e9ce'), ObjectId('69fdaac4eabd702ea246e9cf'), ObjectId('69fdaac4eabd702ea246e9d0')], acknowledged=True)" ] }, "execution_count": 40, "metadata": {}, "output_type": "execute_result" } ], "execution_count": 40 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Teilaufgabe 2 (3 Punkte): \n", "\n", "Erstellen Sie jetzt noch eine Funktion, die einen Überblick über alle Tiere im Zoo gibt, die Ausgabe soll dabei dem Beispiel ähneln." ] }, { "cell_type": "code", "metadata": { "ExecuteTime": { "end_time": "2026-05-08T09:20:07.632673893Z", "start_time": "2026-05-08T09:20:07.598404039Z" } }, "source": [ "def zoo_overview():\n", " result = db.animals.aggregate([\n", " {\n", " \"$lookup\": {\n", " \"from\": \"zookeepers\",\n", " \"localField\": \"zookeeper_id\",\n", " \"foreignField\": \"_id\",\n", " \"as\": \"zookeeper\"\n", " }\n", " },\n", " {\n", " \"$project\": {\n", " \"name\": 1,\n", " \"species\": 1,\n", " \"zookeeper_name\": \"$zookeeper.name\"\n", " }\n", " },\n", " {\n", " \"$unwind\": \"$zookeeper_name\",\n", " }\n", " ])\n", "\n", " animals = []\n", "\n", " for animal in result:\n", " animals.append(animal)\n", "\n", " col_widths = (\n", " max([len(animal.get(\"name\")) for animal in animals]),\n", " max([len(animal.get(\"species\")) for animal in animals]),\n", " max([len(animal.get(\"zookeeper_name\")) for animal in animals]),\n", " )\n", "\n", " print(\"-\" * (sum(col_widths) + 10))\n", " for animal in animals:\n", " print(f\"| {animal.get(\"name\"):{col_widths[0]}} | {animal.get(\"species\"):{col_widths[1]}} | {animal.get(\"zookeeper_name\"):{col_widths[2]}} |\")\n", " print(\"-\" * (sum(col_widths) + 10))\n", "\n", "# Beispielausgabe:\n", "# \n", "# ----------------------------------------\n", "# | Babar | Elephant | John Doe |\n", "# | Dumbo | Elephant | John Doe |\n", "# | Hathi | Elephant | John Doe |\n", "# | Melman | Giraffe | Jane Doe |\n", "# | Gloria | Giraffe | Jane Doe |\n", "# ----------------------------------------\n", "\n", "# Testaufruf\n", "zoo_overview()" ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "--------------------------------\n", "| Babar | Elephant | John Doe |\n", "| Dumbo | Elephant | John Doe |\n", "| Gloria | Giraffe | Jane Doe |\n", "--------------------------------\n" ] } ], "execution_count": 41 }, { "cell_type": "markdown", "metadata": {}, "source": [ "### Teilaufgabe 3 (3 Punkte): \n", "\n", "Begründen Sie, warum Sie die Struktur der Datenbank so gewählt haben, wie Sie es getan haben. \n", "\n", "Welche Vor- und Nachteile hat Ihre Lösung (für volle Punktzahl sollten Sie mindestens 2 Vor- und 2 Nachteile nennen)?\n" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Die Datenbank wurde mit zwei getrennten Collections (zookeepers und animals) umgesetzt, wobei Tiere über eine zookeeper_id auf ihren Tierpfleger verweisen (Referenzierung). Alternativ hätte man die Tiere direkt als Array in das Tierpfleger-Dokument einbetten können (Embedding). Die Referenzierung wurde gewählt, da Tiere auch unabhängig von ihrem Tierpfleger abgefragt werden sollen und die Tierliste potenziell sehr gross werden kann. Embedding würde dabei zu sehr grossen Dokumenten führen.\n", "\n", "Vorteile:\n", "Tiere können unabhängig von Tierpflegern abgefragt und aktualisiert werden, ohne das gesamte Tierpfleger-Dokument zu laden\n", "Skalierbar: Auch bei vielen Tieren pro Tierpfleger wächst das Tierpfleger-Dokument nicht an (MongoDB hat ein 16 MB Dokumentlimit)\n", "\n", "Nachteile:\n", "MongoDB erzwingt keine referentielle Integrität: Ein Tier kann eine zookeeper_id referenzieren, die nicht existiert, ohne dass ein Fehler auftritt\n", "Abfragen, die Daten aus beiden Collections kombinieren (z. B. „alle Tiere mit Tierpfleger-Name\"), erfordern $lookup-Aggregationen, was im Vergleich zu einem SQL-JOIN aufwändiger ist (In Teilaufgabe 2 zu sehen)." ] } ], "metadata": { "kernelspec": { "display_name": "Python [conda env:base] *", "language": "python", "name": "conda-base-py" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.0" } }, "nbformat": 4, "nbformat_minor": 2 }