滚动新闻 →
加拿大权利与自由宪章如何形成 蔡奇北京旧部夏林茂落马 已被掌握把柄及被抄家 上海一保安便利店刷卡被拒 才知莫名负债近百万 欧洲人为什么如此渴望寻找新大陆 中国女星白鹿名下公司均注销 30天掉粉超144万 外墙木板腐烂怎么处理 广州一女子地铁站看书 被扣15元超时费 黄逸豪遭中共跨境追杀 接蒋万安电话呼吁立法 AI 模型 A/B 测试应该怎样设计,技术指标和模型效果如何分别衡量 湖北小学生上课想去厕所被拒 只好尿裤子里 台股震荡逾千点收跌846点 日经重挫1713点 Firestore 数据模型怎么设计,关系型数据库开发人员需要改变哪些思路 为什么 SaaS 不应该让用户请求直接等待大型任务完成?异步任务怎么设计 笔记本充电口松动导致断充,接口损坏时应该如何确认 台风外围环流助燃 苗栗育苗场仓库火灾浓烟蔽日 Windows 11 UAC 用户账户控制怎么设置?安全和便利应该怎样平衡 号称重返20岁 “尸皮针”原料来自逝者 38岁女被捕 MySQL 字符集怎么设置?中文网站避免乱码必须掌握的基础知识 从《岳阳楼记》看古代文人的责任意识 美军台海冲突应对方案:首日即启动全域作战部署 法国骚乱中抢夺iPhone遭反噬 暴徒意外发现手机成追踪定位器 花生在中国传统饮食中的历史 初学者如何选择第一本字帖 台湾艺人遭跨境暴力威胁 矢板明夫怒斥中共输出威权恐惧 希腊雅典市中心建筑爆炸致4人受伤 霍尔木兹海峡关闭致巴拿马运河货运量创新高 孩子总想争第一怎么办 台风蔷琵路径西调 台湾或于今午发布陆警 视频拍摄时存储卡应该如何选择 元朝为什么能够迅速建立横跨欧亚的帝国 PHP核心漏洞引发全球网络安全警报 七成网站面临风险 台湾相声演员因讽刺习遭跨境追杀 旧房家具太多应该如何重新布局 马斯克推动SpaceX与特斯拉合并计划 厄尔尼诺现象或创历史最强纪录 全球极端天气频发引警报 爱马仕柏金包热潮消退 二手市场价格回落 中共公安密件曝光 18种阴招打压“重点人” 包子为什么会遍布中国各地 美国退休教师史蒂芬·哈伯德结束四载俄方羁押返美 三峡工程能回本吗?

Firestore 数据模型怎么设计,关系型数据库开发人员需要改变哪些思路

发布时间: 2026-10-22 01:24:01    最后更新: 2026-10-22 02:35:27    阅读:8  约10 分钟阅读     

Firestore 数据模型怎么设计,关系型数据库开发人员需要改变哪些思路
图片说明:示意图   图片来源:Public Domain(公有领域)
Firestore 是 Google 提供的 NoSQL 文档数据库。对于长期使用 MySQL、PostgreSQL、SQL Server 或 Oracle 的开发人员来说,真正困难的地方通常不是学习几个 API,而是改变数据建模的方法。关系型数据库习惯从表、主键、外键、范式和 JOIN 出发,而 Firestore 更强调文档、集合、子集合、索引以及实际的数据访问模式。

Firestore 的基本存储单位是 document,文档属于 collection。一个文档可以包含字符串、数字、时间戳、数组以及嵌套对象,也可以在文档下面建立 subcollection。与关系型数据库不同,Firestore 是 schemaless 的,同一个 collection 中的文档可以拥有不同字段,但为了查询和应用逻辑保持稳定,实际项目仍然应该尽量保持字段名称和数据类型的一致性。

因此,关系型数据库开发人员进入 Firestore 后首先需要改变的,是“先设计表,再考虑查询”的习惯。Firestore 更适合从“这个业务页面到底需要读取什么数据”开始设计。例如一个电商订单页面可能需要同时显示订单基本信息、客户名称、商品摘要和配送状态。如果这些信息每次都需要通过多个关系表 JOIN 才能得到,那么在 Firestore 中就应该重新考虑数据结构,而不是机械地把原来的几张 SQL 表逐张转换成 collection。

例如用户数据可以设计成:

{
"name": "张三",
"address": {
"city": "上海",
"zip": "200000"
}
}

如果设备数量非常少,而且读取用户资料时总是需要同时显示设备信息,可以把设备作为数组保存。但如果设备数量不断增加、设备独立更新,或者需要按照设备状态、型号和更新时间单独查询,那么把设备全部塞进用户文档就不是一个好的长期设计。此时更适合使用:

users/{userId}/devices/{deviceId}

这种 subcollection 结构。

这体现了 Firestore 与关系型数据库最重要的区别之一:不是所有“关系”都应该被转换成一张独立关系表,也不是所有相关数据都应该塞进一个巨大文档。真正需要考虑的是数据是否经常一起读取、是否独立更新、数量是否会增长以及是否需要单独查询。

反规范化在 Firestore 中非常常见。例如订单文档可以保存 customerId,同时保存结算时使用的客户名称。这样订单列表就不必为了显示客户名称而额外读取用户文档。这里的数据重复并不一定是设计错误,因为它可能换来更简单的读取路径。

但反规范化也会产生同步问题。如果客户名称发生变化,而数千个订单文档中都保存着旧名称,那么应用就需要决定是否批量更新这些历史数据,还是明确规定订单中的客户名称属于交易发生时的快照。后者往往反而更合理,因为订单历史本来就不应该随着客户资料变化而被重新改写。

因此,Firestore 的“数据冗余”不能简单理解为“越少越好”。关系型数据库通常强调规范化以减少重复,而 Firestore 更强调针对读取模式进行合理的数据组织。数据重复是否值得,最终要看读取成本、写入成本、数据一致性要求以及业务语义。

多对多关系同样需要改变思路。例如用户关注用户的社交关系,如果一个用户只有几十个关注对象,可以考虑数组;但如果一个用户可能拥有数千甚至数万条关系,就不应该把所有关系无限堆积在一个用户文档里。可以建立独立的关系 collection,例如:

follows/{followId}

其中保存:

{
"followerId": "userA",
"followedId": "userB",
"createdAt": "..."
}

如果业务同时需要查询“我关注了谁”和“谁关注了我”,就需要针对这两种访问方式设计相应字段和索引,而不是期待 Firestore 像 SQL 数据库一样临时执行 JOIN。

这也是 Firestore 查询设计的核心。Firestore 没有关系型数据库意义上的 JOIN,查询主要围绕 collection、document、where 条件、排序、limit 和 cursor 展开。官方文档也明确支持组合过滤和排序,并通过索引执行查询。

因此,开发人员应该先列出实际查询,例如“查询某个用户最近30天的订单”“查询某个城市中处于配送状态的订单”“查询某个设备最近100条日志”,然后反过来设计字段和索引。

分页尤其如此。不要把关系型数据库中的 OFFSET 100000 思维原封不动搬过来。Firestore 支持 query cursor,可以利用 startAt()、startAfter() 等方式从上一次查询的位置继续读取。典型做法是第一次读取一批文档,保存最后一个文档作为下一页的 cursor,然后继续查询。

索引也应该从实际查询出发。Firestore 的查询依赖索引,复杂查询可能需要 composite index。开发人员不应该简单地为所有字段建立大量组合索引,而应该根据真实查询模式设计索引。当前 Firestore 的索引配额也远不是“一个索引最多5个字段”这么简单,数据库级 composite index 配额取决于当前数据库配置和计费状态。

另一个经常被关系型数据库开发人员误解的问题是事务。

Firestore 并不是简单的“最终一致性数据库”。Google 当前官方文档明确说明 Cloud Firestore 提供 strong consistency,并且事务具有 serializable isolation。事务中的读取和写入具有原子性,如果并发修改导致数据竞争,Firestore 可以重新执行事务,直到成功或者因为竞争等原因失败。

因此,真正需要改变的不是“从强一致性转向最终一致性”,而是理解 Firestore 的事务边界和数据竞争机制。事务适合用于“读取当前状态,然后根据这个状态决定写入结果”的场景。例如账户余额、库存数量或者需要避免并发覆盖的状态更新,都可能需要事务。

同时,不能把事务当成一个可以无限扩大的 SQL transaction。Firestore 事务存在请求大小、时间和其他资源限制。当前官方限制包括单次 API 请求最大10 MiB,事务最长270秒,并且60秒没有活动会触发空闲超时;具体操作还受到字段转换等限制。

事务还可能因为数据竞争而自动重试。因此事务函数不能包含不可重复执行的外部副作用。例如不要在事务函数内部直接发送一封邮件、扣除外部支付账户或者调用一个不可幂等的第三方 API,然后假定事务只会执行一次。Firestore 官方文档也明确提醒,事务函数可能因为并发修改而运行多次。

对于关系型数据库开发人员来说,这一点非常重要。SQL 世界中经常把业务逻辑包在一个 transaction 里,然后按照顺序执行大量操作;Firestore 更适合把真正需要原子性的状态变化缩小到明确的事务边界,其余工作通过事件、任务队列或幂等的异步处理完成。

Firestore 的另一个设计重点是文档大小和增长方式。一个文档并不是无限大的容器,因此不能把一个不断增长的日志列表、聊天记录或者订单历史全部放进某个用户文档。数量不断增长的数据通常应该拆成 collection 或 subcollection,使每个文档保持相对稳定。

嵌套数据也不是越深越好。Firestore 支持 nested maps 和 arrays,但存在字段深度限制,目前最大字段深度为20层。这个限制并不意味着“所有项目都应该保持2至3层”,真正的工程原则应该是让数据结构围绕业务访问路径保持清晰,避免形成巨大、频繁修改而且难以独立查询的文档。

安全模型也是从 SQL 数据库迁移到 Firestore 时必须重新理解的部分。客户端直接访问 Firestore 时,开发人员通常通过 Firebase Authentication 配合 Firestore Security Rules 控制访问。Rules 不应该被当成传统数据库中的一层简单 WHERE 条件,而应该根据用户身份、文档路径和业务状态设计访问控制。对于事务和批量写入,Security Rules 还有额外的文档访问调用限制,因此复杂规则也可能成为系统设计的一部分。

最终,关系型数据库开发人员真正需要改变的思维可以概括为几个问题:这个数据最常见的读取方式是什么?哪些字段应该一起读取?哪些数据会独立增长?哪些关系需要单独查询?哪些数据可以合理冗余?哪些状态必须通过事务保持原子性?哪些操作可以异步化?

如果把 MySQL 的表直接一张一张搬成 Firestore collection,通常只是把关系型数据库换了一个外壳。真正的 Firestore 设计应该从业务访问模式重新开始。

关系型数据库擅长表达复杂关系和通过 JOIN 临时组合数据,而 Firestore 更强调围绕访问路径组织文档,并利用索引、冗余、subcollection 和事务完成高频业务操作。两种数据库没有简单的先进与落后之分,关键是数据模型是否与应用的实际工作方式匹配。对于关系型数据库开发人员来说,最大的转变也正是从“数据之间是什么关系”进一步走向“应用究竟怎样读取和修改这些数据”。

喜欢这篇报道?

使用下面的功能,方便以后继续阅读和分享 MNewsTV

设为 Google 新闻首选来源 让 Google 新闻优先显示 MNewsTV 的最新报道 ›
★ 我的收藏 查看已经收藏的文章
关于文章收藏 收藏不需要注册帐号,收藏信息仅保存在当前浏览器中。 删除收藏请进入「我的收藏」进行管理。
分享这篇报道

捐助(Paypal): https://www.paypal.me/observeccp
订阅中国观察电报 Telegram : https://t.me/s/ObserveCCP