删除(输出阶段)
说明
delete() 是一个数据操纵语言 (DML) 阶段,允许查询根据查询结果移除文档。此阶段可以附加到查询末尾,并将删除上一个阶段的 __name__ 字段引用的所有文档。
示例
删除过时数据
例如,以下查询会删除 address.users 设置为 USA 且 __create_time__ 少于 10 天的所有 users 文档:
Node.js
const pipeline = db.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").timestampAdd("day", 10).lessThan(currentTimestamp())) .delete(); await pipeline.execute();
Python
from google.cloud.firestore_v1.pipeline_expressions import CurrentTimestamp, Field snapshot = ( client.pipeline() .collection_group("users") .where(Field.of("address.country").equal("USA")) .where( Field.of("__create_time__") .timestamp_add("day", 10) .less_than(CurrentTimestamp()) ) .delete() .execute() )
Java
Pipeline.Snapshot deleteResults = firestore.pipeline() .collectionGroup("users") .where(field("address.country").equal("USA")) .where(field("__create_time__").add(constant(10)).lessThan(currentTimestamp())) .delete() .execute().get();
Go
snapshot := client.Pipeline(). CollectionGroup("users"). Where(firestore.FieldOf("address.country").Equal("USA")). Where(firestore.FieldOf("__create_time__").Add(firestore.ConstantOf(10)).LessThan(firestore.CurrentTimestamp())). Delete(). Execute(ctx)
行为
以下部分介绍了 delete() 阶段的执行行为、响应和限制。
响应
delete() 阶段始终会发出一个文档(如 { documents_modified: 28L }),用于描述已删除的文档数量。
删除整个集合
通过将 delete() 附加到输入集合阶段,可以删除集合中的所有文档:
Node.js
```js const results = await db.pipeline() .collection("/users") .delete() .execute(); ```Java
```java Pipeline pipeline = db.pipeline() .collection("/users") .delete(); pipeline.execute(); ```最终阶段
delete() 阶段必须位于流水线的末尾,不能再提供其他阶段。
删除所有 / 边界工作负载
默认情况下,delete() 阶段会移除上一个阶段引用的所有文档。如果您想限制工作负载的大小,或者您知道过滤条件与一个文档完全匹配,则可以在最终 delete() 之前添加 limit(...) 阶段,以限制总工作量。
跨集合变更
最终的 delete() 阶段会将变更应用于 __name__ 引用的任何文档(假设提供了所有必要的身份验证)。这包括在同一请求中从多个不同的集合或集合组中删除文档。
__name__ 必需
delete() 阶段要求前一阶段提供一个 __name__ 字段,其中包含要移除的文档引用。否则会导致运行时错误,并且在事务之外运行时可能会导致部分成功。
大多数输入阶段(例如 collection(...)、collection_group(...)、database(...) 和 documents(...))默认包含 __name__ 字段,因此只有在使用投影(例如 select(...))或对文档执行转换(例如 aggregate(...))时,此字段才相关。
响应
响应包含已修改文档数量的摘要。 例如,以下响应确认流水线修改了三个文档:
{documents_modified: 3L}
限制
现在可以在事务中运行 DML 阶段。在大多数情况下,
insert()和upsert()阶段需要在事务中运行。在新事务中执行具有 DML 阶段的流水线时,您可以使用
atomic选项在事务中自动运行,并在流水线成功执行后提交。在事务中运行时,其他阶段(例如
where、addFields、union、findNearest和aggregate子查询)没有任何限制。事务性 DML 操作受 Firestore 企业版事务限制的约束。由于事务不允许在首次写入后进行读取,因此您无法在单个事务中多次调用 DML 流水线,也无法在 DML 流水线执行后读取文档。在 DML 写入后尝试执行读取操作会失败,并显示FAILED_PRECONDITION错误:Cannot have reads after the first write in a Firestore transaction.在事务之外运行时:
- 每个文档都是独立更新的,并且跨文档的写入操作不具有原子性。流水线会在遇到第一个错误时停止,从而导致部分成功。
- 不支持高级多查询阶段(
aggregate、distinct、unnest、find_nearest、union、联接和子查询)。
在 Firebase 安全规则下,每批文档都会重新评估规则并执行查找。如果规则使用
get()或exists(),则在写入大约 200 个文档后,会达到全局 20 次查找限制,并且操作会失败,并显示PERMISSION_DENIED。请使用自定义声明,而不是get()/exists()查找,以避免此限制。如果 DML 阶段之前的阶段生成了多个具有相同
__name__的文档,或计算结果为相同的目标文档 ID,则每个变更都会按顺序处理:- 对于
upsert(...)和update(...):针对同一文档的多个变更遵循“最后一次变更生效”语义,即最后处理的变更决定文档的最终状态。 - 对于
delete(...):第一次尝试会删除文档,而对同一文档的后续尝试则不执行任何操作。 - 对于
insert(...):第一次尝试会创建文档,而后续针对同一文档 ID 的尝试会失败,并显示ALREADY_EXISTS错误。
- 对于
事务性执行
DML 操作可以作为读写事务的一部分执行,方法是向流水线执行调用提供显式事务,或使用 atomic 选项。
Firestore 事务要求所有读取操作在任何写入操作之前执行。由于 DML 流水线会执行写入操作,因此在同一事务中运行 DML 流水线后,您无法执行读取操作(例如文档查找或查询读取)。例如,您不能在单个事务中多次调用 DML 流水线。在 DML 流水线执行后尝试读取失败,并显示 FAILED_PRECONDITION 错误:Cannot have reads after the first write in a Firestore transaction.