从头开始设计 Firestore 数据库很困难。在编写第一行代码之前,您需要考虑查询、反规范化、子集合和十几个其他 NoSQL 特定问题。与其从零开始,不如使用这 10 个经过验证的模式作为模板。每个都代表一个常见的应用程序架构 — 电子商务、聊天、多租户 SaaS、基于位置的服务 — 带有完整的 JSON Schema,准确显示如何建模集合。复制适合您用例的模式,根据需求进行调整,您将在几分钟而不是几周内拥有坚实的基础。
1. 用户配置文件
社交应用、SaaS 平台、会员网站
Collection Structure
firestore_structures.pattern1_structure
{
"$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: 将用户配置文件存储为根级文档,使用 Firebase Auth UID 作为文档 ID。反规范化常访问的字段,如 displayName 和 photoURL,以便它们可以嵌入到其他集合中而无需额外读取。
Common mistake: 除非用户设置或首选项有数百个项,否则不要将其嵌套为子集合。保持用户文档精简且快速读取。
2. 电子商务产品和订单
在线商店、市场、库存系统
Collection Structure
firestore_structures.pattern2_structure
{
"$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: 将订单存储为带有 userId 的根级文档以进行过滤。将产品名称和价格反规范化到订单项中,以便即使产品数据稍后更改,历史订单仍然准确。
Common mistake: 不要在产品文档中存储库存计数 — 使用单独的库存集合或 Cloud Functions 来防止热门产品上的竞态条件。
3. 聊天和消息
实时聊天应用、客户支持、协作工具
Collection Structure
firestore_structures.pattern3_structure
{
"$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: 对消息使用子集合,以便每个聊天室可以容纳无限消息。反规范化 authorName 以避免为每个消息显示获取用户配置文件。在父 chatRoom 中存储 lastMessage 以进行快速预览渲染。
Common mistake: 不要尝试在 Firestore 文档中实现已读回执或输入指示器 — 对临时在线状态数据使用 Realtime Database 或 Firebase Cloud Messaging。
4. 带评论的博客
内容平台、CMS、社区论坛
Collection Structure
firestore_structures.pattern4_structure
{
"$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: 将帖子存储为根文档,带有反规范化的作者信息以进行高效的列表渲染。保持一个通过 Cloud Functions 更新的缓存 commentCount,以避免仅为显示计数而读取整个评论子集合。
Common mistake: 不要将完整的评论列表作为数组存储在帖子文档中 — 一旦您有超过几十条评论,它就会崩溃,并使分页变得不可能。
5. 多租户 SaaS
B2B 应用程序、基于工作区的工具、团队管理
Collection Structure
firestore_structures.pattern5_structure
{
"$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: 使用 organizations 作为顶级集合,所有租户数据嵌套在下面。这使安全规则变得简单:用户只能访问其组织内的数据。将成员角色存储在子集合中以便于枚举。
Common mistake: 不要将组织数据复制到用户文档中 — 它会产生同步问题。相反,按用户成员资格过滤的 organizations 集合进行查询。
6. 活动和审计日志
合规性跟踪、用户活动源、管理仪表板
Collection Structure
firestore_structures.pattern6_structure
{
"$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: 将活动日志存储为带有 userId、action 和 timestamp 索引字段的根集合。通过 Cloud Functions 在文档写入时生成日志条目,以确保即使客户端代码失败也能完成审计跟踪。
Common mistake: 不要尝试将日志存储为用户或资源下的子集合 — 这使得跨用户或跨资源查询变得不可能。使用带引用字段的扁平集合。
7. 地理定位和地图
基于位置的服务、配送应用、商店查找器
Collection Structure
firestore_structures.pattern7_structure
{
"$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: 在 GeoPoint 字段旁边存储 geohash 字符串以启用高效的邻近查询。Firestore 无法进行本地半径搜索,因此 geohash 允许您按前缀过滤以查找附近的位置。使用像 geofire-common 这样的库来生成哈希。
Common mistake: 不要尝试直接按纬度/经度范围查询 — Firestore 无法进行复合不等式查询。始终使用 geohash 前缀进行基于位置的过滤。
8. 库存管理
仓库系统、库存跟踪、供应链应用
Collection Structure
firestore_structures.pattern8_structure
{
"$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: 更新 quantity 时使用事务以防止竞态条件。对于频繁更新的高容量库存,考虑使用分布式计数器或单独的事务日志集合以避免写入争用。
Common mistake: 不要从客户端代码递增/递减 quantity 字段而不使用事务 — 在并发访问下您会得到不正确的计数。使用 Cloud Functions 或服务器端逻辑。
9. 社交动态和关注者
社交网络、新闻源、活动流
Collection Structure
firestore_structures.pattern9_structure
{
"$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: 将 followers 和 following 存储为每个用户下的单独子集合,以在两个方向上启用高效查询。保持一个通过 Cloud Functions 更新的缓存 likeCount,而不是读取整个 likes 子集合。
Common mistake: 不要在写入时将帖子展开到所有关注者的动态中 — 它无法扩展。相反,使用关注 ID 上的 array-contains 查询实时查询来自关注用户的帖子。
10. IoT 和传感器数据
IoT 仪表板、环境监测、设备遥测
Collection Structure
firestore_structures.pattern10_structure
{
"$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: 将时间序列数据存储为每个设备下的子集合。对于高频数据,批量写入并通过 Cloud Functions 实现 TTL 清理以避免无限增长。考虑 Cloud Firestore TTL 策略或 BigQuery 导出用于长期分析。
Common mistake: 如果您的设备每秒报告一次,不要存储每个传感器读数 — 您会超过 Firestore 的写入限制和成本。聚合到分钟或小时间隔,或对高频写入使用 Realtime Database。
将这些模式转化为文档
这些 JSON Schema 不仅仅是示例 — 它们是您可以在项目中使用的工作文档。将它们保存为代码仓库中的 .schema.json 文件,使用 FireSchema 渲染它们,并为您的团队提供一个他们实际会使用的可浏览参考。设置只需 5 分钟。
下一步
既然您有了可使用的模式,请学习如何有效使用它们: