后端【免费下载链接】angularfireAngular Firebase ❤️项目地址https://gitcode.com/gh_mirrors/an/angularfire点击查看免费下载本文以 docs/compat/firestore/collections.md 为骨架结合仓库内src/compat/firestore的源码与测试系统讲解 AngularFire 兼容版compatAPI 中AngularFirestoreCollection的用法如何创建集合引用、如何用四种流式方法消费集合数据、如何按事件类型过滤变更、以及如何对集合进行增删改查。读完本文你将掌握在 Angular 组件中安全、高效地操作 Cloud Firestore 集合的全部技能并理解每种流式 API 背后的实现原理与适用场景。注意本文面向的是 AngularFire 的compat兼容版本API即从angular/fire/compat/firestore导入的模块。AngularFire 现已提供新的 tree-shakable API关于两套 API 的差异与迁移可参考 v7 升级指南新 API 的入口概览见 README 开发者指南仓库根目录 README.md。1. 集合Collection在 Cloud Firestore 中的定位Cloud Firestore 是一个 NoSQL、面向文档的数据库。与 SQL 数据库不同它没有表和行的概念而是把数据存储在文档document中文档再被组织进集合collection。每个文档包含一组键值对Cloud Firestore 针对存储大量小文档的集合做了专门优化。理解这三个层次有助于把握后续 API 的边界集合一组文档的容器本身不直接存数据只包含文档引用文档真正承载键值对数据的最小单元拥有唯一的文档 ID子集合sub-collection文档内部还可以再嵌套集合形成任意深度的层级结构见 documents.md。在 AngularFire compat 版本中与集合交互的入口就是本文的主角AngularFirestoreCollection。2.AngularFirestoreCollection集合的强类型包装服务AngularFirestoreCollection是对原生 Firestore SDK 的CollectionReference与Query类型的包装服务。它是一个泛型服务通过类型参数为你提供强类型的数据操作与数据流方法设计上可用于Injectable()注入但通常由AngularFirestore服务的collection()方法创建很少直接手动实例化。从源码看它的构造函数接收三个参数collection.tsrefCollectionReferenceT集合的原始引用queryQueryT可选查询未查询时即集合引用本身afsAngularFirestore服务实例。源码注释特别强调了一个易踩坑的设计collection.ts数据操作add/doc().set等作用在ref引用上而不是query查询上。也就是说如果给集合绑定了where、orderBy等查询条件新增的文档不一定会出现在查询结果窗口中——只有满足查询条件的数据才会。AssociatedReference类型在 interfaces.ts 中对该语义做了详细说明。2.1 基本使用示例import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; export interface Item { name: string; } Component({ selector: app-root, template: ul li *ngForlet item of items | async {{ item.name }} /li /ul }) export class AppComponent { private itemsCollection: AngularFirestoreCollectionItem; items: ObservableItem[]; constructor(private afs: AngularFirestore) { this.itemsCollection afs.collectionItem(items); this.items this.itemsCollection.valueChanges(); } addItem(item: Item) { this.itemsCollection.add(item); } }要点拆解afs.collectionItem(items)创建指向items集合的强类型集合服务valueChanges()返回ObservableItem[]配合模板中的async管道自动订阅/退订add(item)向集合写入新文档由 SDK 自动生成文档 ID。AngularFirestore.collection()还支持传入一个queryFn回调来构建查询例如afs.collection(items, ref ref.where(user, , davideast).limit(10))见 firestore.ts 与 interfaces.ts 中QueryFn的定义。2.2DocumentChangeAction类型除了valueChanges()其余流式方法返回的都是ObservableDocumentChangeAction[]。DocumentChangeAction携带两个属性typeDocumentChangeType标明发生了哪种操作——added新增、modified修改、removed删除payloadDocumentChange包含变更的元数据其doc属性是DocumentSnapshot。对应的类型定义在源码 interfaces.ts 中与原生 SDK 对齐interface DocumentChangeActionT { type: DocumentChangeType; payload: DocumentChangeT; } interface DocumentChangeT { type: DocumentChangeType; doc: QueryDocumentSnapshotT; oldIndex: number; newIndex: number; } interface DocumentSnapshot { exists: boolean; ref: DocumentReference; id: string; metadata: SnapshotMetadata; data(): DocumentData; get(fieldPath: string): any; }其中oldIndex/newIndex表示文档在查询结果数组中的旧/新位置索引是判断排序变化的关键元数据。3. 流式读取集合数据的四种方式AngularFirestoreCollection提供四种流式方法它们共享同一份底层快照流但消费方式与语义各不相同。下表可快速对比方法返回类型排序语义是否累积历史典型场景valueChanges()ObservableT[]按查询顺序同步否页面简单列表渲染snapshotChanges()ObservableDocumentChangeAction[]按查询顺序同步否需要文档 ID / 元数据、集成 ngrxstateChanges()ObservableDocumentChangeAction[]按发生顺序非排序否自行在 reducer 中构建数据结构auditTrail()ObservableDocumentChangeAction[]按发生顺序是事件回放、调试、审计日志3.1valueChanges({ idField?: string })是什么集合当前状态的快照流。返回一个同步的 JSON 对象数组剥离所有 Snapshot 元数据只保留文档数据。为什么用它只需要一份数据列表时。结果数组不附带任何文档元数据渲染视图最简单直接。什么时候不用它当你需要比数组更复杂的数据结构时。最佳实践用于页面数据展示简单而有效需求变复杂后改用.snapshotChanges()。可选参数idField传入一个包含idField键的对象后返回的每个 JSON 对象会额外带上文档 ID映射到以idField命名的属性上。从实现看collection.tsvalueChanges()底层走fromCollectionRef快照流再经map对每个文档执行a.data()拆包若指定了idField则用展开运算符把{ [options.idField]: a.id }合并进数据对象。持久化文档 ID 的完整示例当你想在前端把文档 ID作为业务字段持久化保存时可以结合AngularFirestore.createId()源码见 firestore.ts实现为this.firestore.collection(_).doc().id即借助一个占位集合生成唯一 ID实现import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; export interface Item { id: string; name: string; } Component({ selector: app-root, template: ul li *ngForlet item of items | async {{ item.name }} /li /ul }) export class AppComponent { private itemsCollection: AngularFirestoreCollectionItem; items: ObservableItem[]; constructor(private readonly afs: AngularFirestore) { this.itemsCollection afs.collectionItem(items); this.items this.itemsCollection.valueChanges({ idField: customID }); } addItem(name: string) { // Persist a document id const id this.afs.createId(); const item: Item { id, name }; this.itemsCollection.doc(id).set(item); } }这里valueChanges({ idField: customID })使流中的每个对象都带customID属性而写入时先用createId()生成 ID、再用doc(id).set(item)按指定 ID 落库前后呼应。3.2snapshotChanges()是什么集合当前状态的同步快照流返回ObservableDocumentChangeAction[]。数组始终按查询顺序query order排序并随远端与本地变更保持同步。为什么用它需要列表数据、同时想保留元数据时。元数据为你提供底层DocumentReference、文档 ID 以及单篇文档在数组中的索引拥有文档 ID 使后续的数据操作方法如按 ID 更新/删除更易用。此外DocumentChangeAction上的type属性对 ngrx reducer、表单状态与动画状态等 Angular 集成非常有用。什么时候不用它需要比数组更复杂的数据结构或需要逐条处理变更发生过程时此时应选stateChanges()。最佳实践用 RxJS 操作符把.snapshotChanges()的数据转换后再交给模板不要把DocumentChangeAction[]直接暴露给模板。示例转换出带 ID 的数据import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; import { map } from rxjs/operators; export interface Shirt { name: string; price: number; } export interface ShirtId extends Shirt { id: string; } Component({ selector: app-root, template: ul li *ngForlet shirt of shirts | async {{ shirt.name }} is {{ shirt.price }} /li /ul }) export class AppComponent { private shirtCollection: AngularFirestoreCollectionShirt; shirts: ObservableShirtId[]; constructor(private readonly afs: AngularFirestore) { this.shirtCollection afs.collectionShirt(shirts); // .snapshotChanges() 返回 DocumentChangeAction[]其中包含 // 每次变更发生了什么的大量信息。如果只想拿数据和 id用 map 操作符转换。 this.shirts this.shirtCollection.snapshotChanges().pipe( map(actions actions.map(a { const data a.payload.doc.data() as Shirt; const id a.payload.doc.id; return { id, ...data }; })) ); } }a.payload.doc.data()取文档数据a.payload.doc.id取文档 ID再展开合并成{ id, ...data }的新对象。实现原理snapshotChanges()在 collection.ts 中调用validateEventsArray归一化事件列表缺省时补全为[added, removed, modified]见同文件 L14-L19随后走sortedChanges管道。sortedChangeschanges.ts内部用scan把逐次的docChanges合并成持续维护的当前数组再用distinctUntilChanged()削减不必要的变更循环。合并逻辑combineChangechanges.ts对added/modified/removed分别处理added按newIndex插入、removed按oldIndex删除、modified在位置变化时先删除旧位再插入新位且通过slice()返回新数组以打破引用相等从而触发 Angular 变更检测。测试 collection.spec.ts 验证了带orderBy(price, desc)查询时位置移动后oldIndex/newIndex的正确性。3.3stateChanges()是什么返回最近发生的变更流类型为ObservableDocumentChangeAction[]。与上面两种同步数组不同它按事件发生顺序发出而非按查询顺序同步。为什么用它上述方法返回按查询顺序排序的同步数组而stateChanges()逐个发出发生了什么。它非常适合 ngrx 集成——你可以在自己的 reducer 方法里构建任意自定义数据结构。什么时候不用它只需要数据列表时。这是AngularFirestore的进阶用法。示例只监听新增事件import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; import { map } from rxjs/operators; export interface AccountDeposit { description: string; amount: number; } export interface AccountDepositId extends AccountDeposit { id: string; } Component({ selector: app-root, template: ul li *ngForlet deposit of deposits | async {{ deposit.description }} for {{ deposit.amount }} /li /ul }) export class AppComponent { private depositCollection: AngularFirestoreCollectionAccountDeposit; deposits: ObservableAccountDepositId[]; constructor(private readonly afs: AngularFirestore) { this.depositCollection afs.collectionAccountDeposit(deposits); this.deposits this.depositCollection.stateChanges([added]).pipe( map(actions actions.map(a { const data a.payload.doc.data() as AccountDeposit; const id a.payload.doc.id; return { id, ...data }; })) ); } }实现原理stateChanges()在 collection.ts 中直接消费docChangeschanges.ts。docChanges基于fromCollectionRef快照流用pairwise()比较前后两次快照从最新快照的docChanges()提取变更当仅有元数据变化如等待状态pending与完成committed之间切换时还会为元数据变化的文档合成modified动作。随后管道用startWithpairwisefilter保证即使集合为空也至少发出一次空数组源码注释明确让开发者知道集合已解析完成最后用pendingUntilEvent与 Angular 的变更检测集成。测试 collection.spec.ts 验证了空集合与带过滤的空集合都会正常发出length 0。3.4auditTrail()是什么返回ObservableDocumentChangeAction[]与stateChanges()类似按发生顺序发出但会持续累积每次变更形成完整的事件轨迹数组。为什么用它stateChanges()是短暂的只发最新一批变更而auditTrail()会把每次变更收集进数组。这对需要重放应用完整状态的 ngrx 集成非常有用同时它也是绝佳的调试工具——直接afs.collection(items).auditTrail().subscribe(console.log)即可在控制台实时观察所有事件。什么时候不用它只需要数据列表时。同样属于进阶用法。示例账户日志import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; import { map } from rxjs/operators; export interface AccountLogItem { description: string; amount: number; } export interface AccountLogItemId extends AccountLogItem { id: string; } Component({ selector: app-root, template: ul li *ngForlet log of accountLogs | async {{ log.description }} for {{ log.amount }} /li /ul }) export class AppComponent { private accountLogCollection: AngularFirestoreCollectionAccountLogItem; accountLogs: ObservableAccountLogItemId[]; constructor(private readonly afs: AngularFirestore) { this.accountLogCollection afs.collectionAccountLogItem(accountLog); this.accountLogs this.accountLogCollection.auditTrail().pipe( map(actions actions.map(a { const data a.payload.doc.data() as AccountLogItem; const id a.payload.doc.id; return { id, ...data }; })) ); } }实现原理auditTrail()的实现极其简洁collection.ts——它就是stateChanges()的输出经过scan((current, action) [...current, ...action], [])累积拼接的结果初始值为空数组每来一批变更就追加到尾部。测试 collection.spec.ts 验证了默认监听全部事件时新增 10 条后再修改 1 条轨迹数组长度变为 11 且末位type modified。3.5 限制事件类型只监听你关心的变更Firestore 有三种DocumentChangeTypeadded、removed、modified。四种流式方法默认全部监听。若你只关心其中若干种可通过每个方法的第一个参数传入事件数组进行过滤基础示例constructor(private afs: AngularFirestore) { this.itemsCollection afs.collectionItem(items); this.items this.itemsCollection.snapshotChanges([added, removed]); }组件示例import { Component } from angular/core; import { AngularFirestore, AngularFirestoreCollection } from angular/fire/compat/firestore; import { Observable } from rxjs; Component({ selector: app-root, template: ul li *ngForlet item of items | async {{ item.name }} /li /ul }) export class AppComponent { private itemsCollection: AngularFirestoreCollectionItem; items: ObservableItem[]; constructor(private afs: AngularFirestore) { this.itemsCollection afs.collectionItem(items); this.items this.itemsCollection.valueChanges([added, removed]); } }注意事件过滤在四种方法中的实现位置不同。snapshotChanges()是把过滤后的事件交给combineChanges参与数组合并仅保留被允许的变更类型进入结果数组changes.tsstateChanges()/auditTrail()则是在docChanges输出后对每个动作按events.includes(change.type)过滤collection.ts。测试 collection.spec.ts 对snapshotChanges([modified])、snapshotChanges([added])、snapshotChanges([added, removed])等过滤场景均有覆盖。4. 状态型state-basedvs 动作型action-based上述四种方法可归为两大类状态型state-based返回集合状态原样呈现。代表是valueChanges()——例如用户修改了列表第 3 项它更新集合中第 3 项并返回一份 JSON 数据数组反映的是现在长什么样。动作型action-based返回集合中发生了什么。代表是snapshotChanges()/stateChanges()/auditTrail()——返回的是DocumentChangeAction[]记录发生了什么变化。结合源码可进一步印证snapshotChanges内部用scan维护当前状态数组状态语义而stateChanges/auditTrail直接透传docChanges的增量动作动作语义。理解这一区分是选择合适流式 API 的关键。5. 向集合添加文档add()要向集合添加新文档自动生成文档 ID使用add()方法。它会用泛型类型参数校验写入数据的类型结构。基础示例constructor(private afs: AngularFirestore) { const shirtsCollection afs.collectionItem(tshirts); shirtsCollection.add({ name: item, price: 10 }); }从实现看collection.tsadd(data)直接委托给底层CollectionReference.add(data)返回PromiseDocumentReferenceT。同样要注意第 2 节提到的语义add()作用在集合引用上与集合绑定的查询条件无关。6. 操作单个文档doc()要检索、更新或删除单个文档使用doc()方法。它返回一个AngularFirestoreDocument后者提供流式读取、更新与删除等方法const itemDoc afs.docItem(items/1); // 或 itemsCollection.doc(1) itemDoc.update({ name: new name }); // 更新部分字段 itemDoc.set({ name: item }); // 创建或整体覆盖 itemDoc.delete(); // 删除文档实现上AngularFirestoreCollection.doc(path)collection.ts通过this.ref.doc(path)拿到底层文档引用并包装为AngularFirestoreDocument文档服务的set/update/delete均是对原生DocumentReference同名方法的直接委托document.ts。文档的完整用法参见 documents.md。7. 下一步与相关资源集合上支持查询过滤、排序与分页参见 querying-collections.md单文档的流式与写入操作参见 documents.md离线数据与持久化行为参见 offline-data.md与本文配套的模块配置AngularFirestoreModule、USE_EMULATOR等见 firestore.module.ts类型与接口定义集中在 interfaces.ts源码入口统一从 public_api.ts 导出单元测试可参考 collection.spec.ts。本文结论速查valueChanges()负责状态其余三种负责动作snapshotChanges()保序、stateChanges()保发生顺序、auditTrail()累积全部历史四种方法均可通过首个参数过滤added/removed/modified事件写入操作add/doc()永远作用于集合引用本身与查询窗口无关。赞分享后端【免费下载链接】angularfireAngular Firebase ❤️项目地址https://gitcode.com/gh_mirrors/an/angularfire点击查看免费下载相关推荐MCP Toolbox 实战指南使用 firestore-query-collection 工具查询 Firestore 集合MCP Toolbox 实战指南使用 firestore query collection 工具查询 Firestore 集合 本指南深入讲解 MCP TooMCP 服务数据库后端AI 应用Hydrogen-v1多通行证(Multipass)认证为企业客户打造无缝登录体验Hydrogen v1多通行证 Multipass 认证为企业客户打造无缝登录体验 Hydrogen v1是基于React的框架专为构建动态的、Shopif前端Web框架电商AngularFirecompat 版Cloud Firestore 离线数据持久化实战指南AngularFirecompat 版Cloud Firestore 离线数据持久化实战指南 Cloud Firestore 的离线数据持久化允许 Web后端上一篇LTX-Video 开源视频生成模型3 步在本地跑通实时文生视频下一篇为什么选择Qwen2.5-32B-Instruct-w8a8揭秘W8A8量化技术的优势创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
