{}FireSchema

10 Estructuras de Base de Datos Firestore que Puedes Copiar

Modelos de datos del mundo real con ejemplos completos de JSON Schema

Diseñar una base de datos Firestore desde cero es difícil. Necesitas pensar en consultas, desnormalización, subcolecciones y una docena de otras preocupaciones específicas de NoSQL antes de escribir tu primera línea de código. En lugar de empezar desde cero, usa estos 10 patrones probados como plantillas. Cada uno representa una arquitectura de app común — e-commerce, chat, SaaS multi-tenant, servicios basados en ubicación — con un JSON Schema completo que muestra exactamente cómo modelar las colecciones. Copia el patrón que se ajuste a tu caso de uso, adáptalo a tus necesidades y tendrás una base sólida en minutos en lugar de semanas.

1. Perfiles de Usuario

Apps sociales, plataformas SaaS, sitios de membresía

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: Almacena perfiles de usuario como documentos de nivel raíz con el UID de Firebase Auth como ID del documento. Desnormaliza campos de acceso frecuente como displayName y photoURL para que puedan incrustarse en otras colecciones sin lecturas extra.

Common mistake: No anides configuraciones o preferencias de usuario como subcolecciones a menos que tengan cientos de elementos. Mantén el documento de usuario ligero y rápido de leer.

2. Productos y Pedidos de E-Commerce

Tiendas online, marketplaces, sistemas de inventario

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: Almacena pedidos como documentos de nivel raíz con userId para filtrado. Desnormaliza nombre y precio del producto en los elementos del pedido para que los pedidos históricos se mantengan precisos incluso si los datos del producto cambian después.

Common mistake: No almacenes conteos de inventario en documentos de producto — usa una colección de inventario separada o Cloud Functions para evitar condiciones de carrera en productos populares.

3. Chat y Mensajería

Apps de chat en tiempo real, soporte al cliente, herramientas de colaboración

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: Usa subcolecciones para mensajes para que cada sala de chat pueda contener mensajes ilimitados. Desnormaliza authorName para evitar obtener perfiles de usuario para cada mensaje mostrado. Almacena lastMessage en el chatRoom padre para renderizado rápido de vista previa.

Common mistake: No intentes implementar confirmaciones de lectura o indicadores de escritura en documentos de Firestore — usa Realtime Database o Firebase Cloud Messaging para datos de presencia efímera.

4. Blog con Comentarios

Plataformas de contenido, CMS, foros comunitarios

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: Almacena posts como documentos raíz con información de autor desnormalizada para renderizado eficiente de listas. Mantén un commentCount en caché actualizado mediante Cloud Functions para evitar leer toda la subcolección de comentarios solo para mostrar un conteo.

Common mistake: No almacenes la lista completa de comentarios en el documento del post como un array — se rompe una vez que tienes más de unas pocas docenas de comentarios y hace imposible la paginación.

5. SaaS Multi-Tenant

Aplicaciones B2B, herramientas basadas en espacios de trabajo, gestión de equipos

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: Usa organizations como la colección de nivel superior con todos los datos del tenant anidados debajo. Esto hace que las reglas de seguridad sean simples: los usuarios solo pueden acceder a datos dentro de su organización. Almacena roles de miembros en una subcolección para enumeración fácil.

Common mistake: No dupliques datos de organización en documentos de usuario — crea problemas de sincronización. En su lugar, consulta la colección organizations filtrada por membresía de usuario.

6. Actividad y Log de Auditoría

Seguimiento de cumplimiento, feeds de actividad de usuario, paneles de administración

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: Almacena logs de actividad como una colección raíz con campos indexados para userId, action y timestamp. Genera entradas de log mediante Cloud Functions en escrituras de documentos para asegurar rastros de auditoría completos incluso si el código del cliente falla.

Common mistake: No intentes almacenar logs como subcolecciones bajo usuarios o recursos — hace imposibles consultas entre usuarios o recursos. Usa una colección plana con campos de referencia.

7. Geolocalización y Mapas

Servicios basados en ubicación, apps de entrega, buscadores de tiendas

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: Almacena strings geohash junto a campos GeoPoint para habilitar consultas de proximidad eficientes. Firestore no puede hacer búsquedas nativas de radio, así que geohash te permite filtrar por prefijo para encontrar ubicaciones cercanas. Usa librerías como geofire-common para generar hashes.

Common mistake: No intentes consultar por rangos de latitud/longitud directamente — Firestore no puede hacer consultas de desigualdad compuesta. Siempre usa prefijos geohash para filtrado basado en ubicación.

8. Gestión de Inventario

Sistemas de almacén, seguimiento de stock, apps de cadena de suministro

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: Usa transacciones al actualizar quantity para prevenir condiciones de carrera. Para inventario de alto volumen con actualizaciones frecuentes, considera usar contadores distribuidos o una colección de log de transacciones separada para evitar contención de escritura.

Common mistake: No incrementes/decrementes campos quantity desde código de cliente sin transacciones — obtendrás conteos incorrectos bajo acceso concurrente. Usa Cloud Functions o lógica del lado del servidor.

9. Feed Social y Seguidores

Redes sociales, feeds de noticias, streams de actividad

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: Almacena followers y following como subcolecciones separadas bajo cada usuario para habilitar consultas eficientes en ambas direcciones. Mantén un likeCount en caché en posts actualizado mediante Cloud Functions en lugar de leer toda la subcolección de likes.

Common mistake: No distribuyas posts a los feeds de todos los seguidores en escritura — no escala. En su lugar, consulta posts de usuarios seguidos en tiempo real usando una consulta array-contains en IDs de following.

10. IoT y Datos de Sensores

Paneles IoT, monitoreo ambiental, telemetría de dispositivos

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: Almacena datos de series temporales como subcolecciones bajo cada dispositivo. Para datos de alta frecuencia, agrupa escrituras e implementa limpieza TTL mediante Cloud Functions para evitar crecimiento sin límite. Considera políticas TTL de Cloud Firestore o exportaciones a BigQuery para analíticas de largo plazo.

Common mistake: No almacenes cada lectura de sensor si tu dispositivo reporta cada segundo — excederás los límites de escritura y costos de Firestore. Agrega a intervalos de minutos u horas, o usa Realtime Database para escrituras de alta frecuencia.

Convierte Estos Patrones en Documentación

Estos JSON Schemas no son solo ejemplos — son documentación funcional que puedes usar en tu proyecto. Guárdalos como archivos .schema.json en tu repositorio, renderízalos con FireSchema y dale a tu equipo una referencia navegable que realmente usarán. Toma 5 minutos configurarlo.

Siguientes Pasos

Ahora que tienes patrones con los que trabajar, aprende cómo usarlos efectivamente:

Probar FireSchema

Guía de Inicio Rápido