{}FireSchema

10 Firestore-Datenbankstrukturen zum Kopieren

Reale Datenmodelle mit vollständigen JSON Schema-Beispielen

Eine Firestore-Datenbank von Grund auf zu entwerfen ist schwierig. Du musst über Queries, Denormalisierung, Untersammlungen und ein Dutzend andere NoSQL-spezifische Aspekte nachdenken, bevor du deine erste Codezeile schreibst. Anstatt bei Null zu beginnen, nutze diese 10 bewährten Muster als Vorlagen. Jedes repräsentiert eine gängige App-Architektur — E-Commerce, Chat, Multi-Tenant-SaaS, standortbasierte Dienste — mit einem vollständigen JSON Schema, das genau zeigt, wie die Sammlungen zu modellieren sind. Kopiere das Muster, das zu deinem Anwendungsfall passt, passe es an deine Bedürfnisse an, und du hast in Minuten statt Wochen eine solide Grundlage.

1. Benutzerprofile

Social Apps, SaaS-Plattformen, Mitgliedschaftsseiten

Collection Structure

firestore_structures.pattern1_structure
schemas/pattern1.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "users",
  "description": "User profiles with authentication info",
  "schema": {
    "type": "object",
    "properties": {
      "displayName": {
        "type": "string",
        "description": "User's full name"
      },
      "email": {
        "type": "string",
        "format": "email",
        "description": "Login email address"
      },
      "photoURL": {
        "type": "string",
        "format": "uri",
        "description": "Profile picture URL"
      },
      "role": {
        "type": "string",
        "enum": ["admin", "editor", "viewer"],
        "description": "Access control role"
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Account creation timestamp"
      }
    },
    "required": ["displayName", "email", "role", "createdAt"]
  }
}

Why this design: Speichere Benutzerprofile als Root-Level-Dokumente mit der Firebase Auth UID als Dokument-ID. Denormalisiere häufig abgerufene Felder wie displayName und photoURL, damit sie in andere Sammlungen eingebettet werden können, ohne zusätzliche Lesevorgänge.

Common mistake: Verschachtele keine Benutzereinstellungen oder -präferenzen als Untersammlungen, außer sie haben Hunderte von Einträgen. Halte das Benutzerdokument schlank und schnell lesbar.

2. E-Commerce-Produkte & Bestellungen

Online-Shops, Marktplätze, Bestandssysteme

Collection Structure

firestore_structures.pattern2_structure
schemas/pattern2.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "orders",
  "description": "Customer purchase orders",
  "schema": {
    "type": "object",
    "properties": {
      "userId": {
        "type": "string",
        "description": "Reference to users collection"
      },
      "items": {
        "type": "array",
        "description": "Ordered items with denormalized product data",
        "items": {
          "type": "object",
          "properties": {
            "productId": { "type": "string" },
            "name": { "type": "string" },
            "price": { "type": "number", "minimum": 0 },
            "quantity": { "type": "integer", "minimum": 1 }
          },
          "required": ["productId", "name", "price", "quantity"]
        }
      },
      "total": {
        "type": "number",
        "minimum": 0,
        "description": "Order total in USD"
      },
      "status": {
        "type": "string",
        "enum": ["pending", "confirmed", "shipped", "delivered"],
        "description": "Current order status"
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Order timestamp"
      }
    },
    "required": ["userId", "items", "total", "status", "createdAt"]
  }
}

Why this design: Speichere Bestellungen als Root-Level-Dokumente mit userId zum Filtern. Denormalisiere Produktname und Preis in Bestellpositionen, damit historische Bestellungen korrekt bleiben, auch wenn sich Produktdaten später ändern.

Common mistake: Speichere keine Bestandszahlen in Produktdokumenten — nutze eine separate Bestandssammlung oder Cloud Functions, um Race Conditions bei beliebten Produkten zu vermeiden.

3. Chat & Messaging

Echtzeit-Chat-Apps, Kundensupport, Kollaborationstools

Collection Structure

firestore_structures.pattern3_structure
schemas/pattern3.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "messages",
  "description": "Chat messages within a room",
  "schema": {
    "type": "object",
    "properties": {
      "authorId": {
        "type": "string",
        "description": "User ID of message author"
      },
      "authorName": {
        "type": "string",
        "description": "Denormalized author display name"
      },
      "text": {
        "type": "string",
        "description": "Message content",
        "maxLength": 5000
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Message timestamp"
      },
      "edited": {
        "type": "boolean",
        "description": "Whether message was edited"
      }
    },
    "required": ["authorId", "authorName", "text", "createdAt"]
  }
}

Why this design: Nutze Untersammlungen für Nachrichten, damit jeder Chat-Raum unbegrenzt viele Nachrichten enthalten kann. Denormalisiere authorName, um das Abrufen von Benutzerprofilen für jede Nachrichtenanzeige zu vermeiden. Speichere lastMessage im übergeordneten chatRoom für schnelles Vorschau-Rendering.

Common mistake: Versuche nicht, Lesebestätigungen oder Tipp-Indikatoren in Firestore-Dokumenten zu implementieren — nutze Realtime Database oder Firebase Cloud Messaging für ephemere Präsenzdaten.

4. Blog mit Kommentaren

Content-Plattformen, CMS, Community-Foren

Collection Structure

firestore_structures.pattern4_structure
schemas/pattern4.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "posts",
  "description": "Blog posts with metadata",
  "schema": {
    "type": "object",
    "properties": {
      "title": {
        "type": "string",
        "description": "Post title",
        "maxLength": 200
      },
      "content": {
        "type": "string",
        "description": "Post body in markdown"
      },
      "authorId": {
        "type": "string",
        "description": "Reference to users collection"
      },
      "authorName": {
        "type": "string",
        "description": "Denormalized author name"
      },
      "publishedAt": {
        "type": "string",
        "format": "date-time",
        "description": "Publication timestamp"
      },
      "commentCount": {
        "type": "integer",
        "minimum": 0,
        "description": "Cached comment count"
      },
      "tags": {
        "type": "array",
        "items": { "type": "string" },
        "description": "Post tags for filtering"
      }
    },
    "required": ["title", "content", "authorId", "authorName", "publishedAt"]
  }
}

Why this design: Speichere Posts als Root-Dokumente mit denormalisierten Autorinformationen für effizientes Listen-Rendering. Halte einen gecachten commentCount über Cloud Functions aktualisiert, um das Lesen der gesamten Kommentar-Untersammlung nur für eine Anzahl zu vermeiden.

Common mistake: Speichere nicht die vollständige Kommentarliste im Post-Dokument als Array — es bricht, sobald du mehr als ein paar Dutzend Kommentare hast, und macht Paginierung unmöglich.

5. Multi-Tenant-SaaS

B2B-Anwendungen, Workspace-basierte Tools, Team-Management

Collection Structure

firestore_structures.pattern5_structure
schemas/pattern5.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "organizations",
  "description": "Tenant organizations for multi-tenant SaaS",
  "schema": {
    "type": "object",
    "properties": {
      "name": {
        "type": "string",
        "description": "Organization name"
      },
      "plan": {
        "type": "string",
        "enum": ["free", "pro", "enterprise"],
        "description": "Subscription plan"
      },
      "ownerId": {
        "type": "string",
        "description": "User ID of organization owner"
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Organization creation timestamp"
      },
      "memberCount": {
        "type": "integer",
        "minimum": 1,
        "description": "Cached member count"
      }
    },
    "required": ["name", "plan", "ownerId", "createdAt"]
  }
}

Why this design: Nutze Organisationen als Top-Level-Sammlung mit allen Tenant-Daten darunter verschachtelt. Das macht Security Rules einfach: Benutzer können nur auf Daten innerhalb ihrer Organisation zugreifen. Speichere Mitgliederrollen in einer Untersammlung für einfache Aufzählung.

Common mistake: Dupliziere keine Organisationsdaten in Benutzerdokumente — es erzeugt Sync-Probleme. Frage stattdessen die Organisationssammlung gefiltert nach Benutzermitgliedschaft ab.

6. Aktivitäts- & Audit-Log

Compliance-Tracking, Benutzeraktivitäts-Feeds, Admin-Dashboards

Collection Structure

firestore_structures.pattern6_structure
schemas/pattern6.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "activityLog",
  "description": "Audit trail of user actions",
  "schema": {
    "type": "object",
    "properties": {
      "userId": {
        "type": "string",
        "description": "User who performed the action"
      },
      "userName": {
        "type": "string",
        "description": "Denormalized user name"
      },
      "action": {
        "type": "string",
        "enum": ["created", "updated", "deleted", "viewed"],
        "description": "Action type"
      },
      "resourceType": {
        "type": "string",
        "description": "Type of resource affected (e.g., 'post', 'user')"
      },
      "resourceId": {
        "type": "string",
        "description": "ID of affected resource"
      },
      "metadata": {
        "type": "object",
        "description": "Additional context data"
      },
      "timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "When the action occurred"
      }
    },
    "required": ["userId", "action", "resourceType", "resourceId", "timestamp"]
  }
}

Why this design: Speichere Aktivitätslogs als Root-Sammlung mit indizierten Feldern für userId, action und timestamp. Generiere Log-Einträge über Cloud Functions bei Dokumentschreibvorgängen, um vollständige Audit-Trails sicherzustellen, auch wenn Client-Code fehlschlägt.

Common mistake: Versuche nicht, Logs als Untersammlungen unter Benutzern oder Ressourcen zu speichern — es macht benutzer- oder ressourcenübergreifende Queries unmöglich. Nutze eine flache Sammlung mit Referenzfeldern.

7. Geolokation & Karten

Standortbasierte Dienste, Liefer-Apps, Geschäftsfinder

Collection Structure

firestore_structures.pattern7_structure
schemas/pattern7.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "locations",
  "description": "Locations with geospatial data",
  "schema": {
    "type": "object",
    "properties": {
      "name": {
        "type": "string",
        "description": "Location name"
      },
      "address": {
        "type": "string",
        "description": "Street address"
      },
      "geopoint": {
        "type": "object",
        "description": "Firestore GeoPoint",
        "properties": {
          "latitude": { "type": "number", "minimum": -90, "maximum": 90 },
          "longitude": { "type": "number", "minimum": -180, "maximum": 180 }
        },
        "required": ["latitude", "longitude"]
      },
      "geohash": {
        "type": "string",
        "description": "Geohash for proximity queries"
      },
      "category": {
        "type": "string",
        "enum": ["restaurant", "store", "office", "other"],
        "description": "Location type"
      }
    },
    "required": ["name", "geopoint", "geohash"]
  }
}

Why this design: Speichere Geohash-Strings neben GeoPoint-Feldern, um effiziente Proximity-Queries zu ermöglichen. Firestore kann keine nativen Radius-Suchen durchführen, daher ermöglicht Geohash das Filtern nach Präfix, um nahegelegene Standorte zu finden. Nutze Bibliotheken wie geofire-common, um Hashes zu generieren.

Common mistake: Versuche nicht, direkt nach Breitengrad-/Längengradbereich zu suchen — Firestore kann keine zusammengesetzten Ungleichheits-Queries durchführen. Nutze immer Geohash-Präfixe für standortbasiertes Filtern.

8. Bestandsverwaltung

Lagersysteme, Bestandsverfolgung, Supply-Chain-Apps

Collection Structure

firestore_structures.pattern8_structure
schemas/pattern8.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "inventory",
  "description": "Inventory items with stock levels",
  "schema": {
    "type": "object",
    "properties": {
      "sku": {
        "type": "string",
        "description": "Stock keeping unit code"
      },
      "name": {
        "type": "string",
        "description": "Item name"
      },
      "quantity": {
        "type": "integer",
        "minimum": 0,
        "description": "Current stock quantity"
      },
      "warehouseId": {
        "type": "string",
        "description": "Warehouse location reference"
      },
      "reorderLevel": {
        "type": "integer",
        "minimum": 0,
        "description": "Quantity threshold for reorder alerts"
      },
      "lastRestocked": {
        "type": "string",
        "format": "date-time",
        "description": "Last restock timestamp"
      }
    },
    "required": ["sku", "name", "quantity", "warehouseId"]
  }
}

Why this design: Nutze Transaktionen beim Aktualisieren von quantity, um Race Conditions zu vermeiden. Für hochvolumigen Bestand mit häufigen Updates erwäge verteilte Zähler oder eine separate Transaktions-Log-Sammlung, um Write-Contention zu vermeiden.

Common mistake: Erhöhe/verringere quantity-Felder nicht aus Client-Code ohne Transaktionen — du erhältst unter gleichzeitigem Zugriff falsche Zählungen. Nutze Cloud Functions oder serverseitige Logik.

9. Social Feed & Follower

Soziale Netzwerke, News-Feeds, Aktivitäts-Streams

Collection Structure

firestore_structures.pattern9_structure
schemas/pattern9.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "posts",
  "description": "Social feed posts",
  "schema": {
    "type": "object",
    "properties": {
      "authorId": {
        "type": "string",
        "description": "User ID of post author"
      },
      "authorName": {
        "type": "string",
        "description": "Denormalized author display name"
      },
      "content": {
        "type": "string",
        "description": "Post content",
        "maxLength": 5000
      },
      "likeCount": {
        "type": "integer",
        "minimum": 0,
        "description": "Cached like count"
      },
      "createdAt": {
        "type": "string",
        "format": "date-time",
        "description": "Post timestamp"
      }
    },
    "required": ["authorId", "authorName", "content", "createdAt"]
  }
}

Why this design: Speichere Follower und Following als separate Untersammlungen unter jedem Benutzer, um effiziente Queries in beide Richtungen zu ermöglichen. Halte einen gecachten likeCount auf Posts über Cloud Functions aktualisiert, anstatt die gesamte Likes-Untersammlung zu lesen.

Common mistake: Verbreite Posts nicht beim Schreiben an alle Follower-Feeds — es skaliert nicht. Frage stattdessen Posts von gefolgten Benutzern in Echtzeit mit einer array-contains-Query auf Following-IDs ab.

10. IoT & Sensordaten

IoT-Dashboards, Umweltüberwachung, Geräte-Telemetrie

Collection Structure

firestore_structures.pattern10_structure
schemas/pattern10.schema.jsonJSON
{
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "collection": "readings",
  "description": "Sensor readings from IoT devices",
  "schema": {
    "type": "object",
    "properties": {
      "temperature": {
        "type": "number",
        "description": "Temperature in Celsius"
      },
      "humidity": {
        "type": "number",
        "minimum": 0,
        "maximum": 100,
        "description": "Relative humidity percentage"
      },
      "batteryLevel": {
        "type": "number",
        "minimum": 0,
        "maximum": 100,
        "description": "Battery percentage"
      },
      "timestamp": {
        "type": "string",
        "format": "date-time",
        "description": "Reading timestamp"
      }
    },
    "required": ["timestamp"]
  }
}

Why this design: Speichere Zeitreihendaten als Untersammlungen unter jedem Gerät. Für hochfrequente Daten bündele Writes und implementiere TTL-Bereinigung über Cloud Functions, um unbegrenztes Wachstum zu vermeiden. Erwäge Cloud Firestore TTL-Richtlinien oder BigQuery-Exporte für Langzeit-Analytics.

Common mistake: Speichere nicht jeden Sensorwert, wenn dein Gerät jede Sekunde berichtet — du überschreitest Firestores Write-Limits und Kosten. Aggregiere zu Minuten- oder Stunden-Intervallen, oder nutze Realtime Database für hochfrequente Writes.

Verwandle diese Muster in Dokumentation

Diese JSON Schemas sind nicht nur Beispiele — sie sind funktionierende Dokumentation, die du in deinem Projekt nutzen kannst. Speichere sie als .schema.json-Dateien in deinem Repository, rendere sie mit FireSchema und gib deinem Team eine durchsuchbare Referenz, die sie tatsächlich nutzen werden. Es dauert 5 Minuten zum Einrichten.

Nächste Schritte

Jetzt, da du Muster zum Arbeiten hast, lerne, wie du sie effektiv einsetzt:

FireSchema ausprobieren

Schnellstart-Anleitung