如何使用过滤器跟踪已删除的文档?
How to track deleted documents with a filter?
我想跟踪对 Firestore 集合中文档的更改。我使用 lastModified
属性 来过滤结果。我使用这个“lastModified”过滤器的原因是每次应用程序启动时,监听器中的初始快照不会 return 集合中的所有文档。
// The app is only interested in changes occurring after a certain date
let date: Date = readDateFromDatabase()
// When the app starts, begin listening for city updates.
listener = db.collection("cities")
.whereField("lastModified", isGreaterThanOrEqualTo: date)
.addSnapshotListener() { (snapshot, error)
// Process added, modified, and removed documents.
// Keep a record of the last modified date of the updates.
// Store an updated last modified date in the database using
// the oldest last modified date of the documents in the
// snapshot.
writeDateToDatabase()
}
每次在闭包中处理文档时,都会在数据库中存储一个新的“lastModified”值。应用程序下次启动时,将使用这个新的“lastModified”值通过查询创建快照侦听器。
创建新的 city
或更新时,其“lastModified”属性 更新为“now”。由于“现在”应该大于或等于筛选日期,因此所有更新都将发送到客户端。
但是,如果删除了一个非常古老的城市,那么它的“lastModified”属性可能比最近收到更新的客户端的过滤日期更早。问题是被删除城市的“lastModified”属性在删除时无法更新为“now”
例子
- 客户端 1 监听更新 ≥ d_1.
- 客户端 2 在 d_2 创建两个城市,其中 d_1 < d_2.
- 客户端 1 收到两个更新,因为 d_1 < d_2.
- 客户端 1 存储 d_2 作为未来的过滤器。
- 客户端 2 在 d_3 更新城市 1,其中 d_2 < d_3。
- 客户端 1 收到此更新,因为 d_1 < d_3.
- 客户端 1 存储 d_3 作为未来的过滤器。
- ...一段时间过去了。
- 客户端 1 应用启动并侦听更新 ≥ d_3。
- 客户端 2 删除城市 2(创建于 d_2)。
- 客户端 1 不会收到此更新,因为 d_2 < d_3.
我的最佳解决方案
不要删除城市,而是添加一个 isDeleted
属性。然后,当一个城市被标记为已删除时,其“lastModified”属性 将更新为“now”。此更新应发送给所有客户端,因为查询过滤器日期始终在“现在”之前。该应用程序的主要业务逻辑忽略了 isDeleted
为 true 的城市。
感觉这个问题我没有完全理解。有没有更好的方法来解决我的问题?
您创建的解决方案非常常见,被称为 tombstone。
由于您不再需要文档的实际数据,您可以删除它的字段。但文档本身需要保留以表明它已被删除。
可能还有其他方法,但它们都会以相似的方式结束。由于您必须以某种方式向每个客户(无论他们何时 connect/query)发出文档已消失的信号,因此将文档保留为墓碑对我来说似乎是一种简单而好的方法。
我想跟踪对 Firestore 集合中文档的更改。我使用 lastModified
属性 来过滤结果。我使用这个“lastModified”过滤器的原因是每次应用程序启动时,监听器中的初始快照不会 return 集合中的所有文档。
// The app is only interested in changes occurring after a certain date
let date: Date = readDateFromDatabase()
// When the app starts, begin listening for city updates.
listener = db.collection("cities")
.whereField("lastModified", isGreaterThanOrEqualTo: date)
.addSnapshotListener() { (snapshot, error)
// Process added, modified, and removed documents.
// Keep a record of the last modified date of the updates.
// Store an updated last modified date in the database using
// the oldest last modified date of the documents in the
// snapshot.
writeDateToDatabase()
}
每次在闭包中处理文档时,都会在数据库中存储一个新的“lastModified”值。应用程序下次启动时,将使用这个新的“lastModified”值通过查询创建快照侦听器。
创建新的 city
或更新时,其“lastModified”属性 更新为“now”。由于“现在”应该大于或等于筛选日期,因此所有更新都将发送到客户端。
但是,如果删除了一个非常古老的城市,那么它的“lastModified”属性可能比最近收到更新的客户端的过滤日期更早。问题是被删除城市的“lastModified”属性在删除时无法更新为“now”
例子
- 客户端 1 监听更新 ≥ d_1.
- 客户端 2 在 d_2 创建两个城市,其中 d_1 < d_2.
- 客户端 1 收到两个更新,因为 d_1 < d_2.
- 客户端 1 存储 d_2 作为未来的过滤器。
- 客户端 2 在 d_3 更新城市 1,其中 d_2 < d_3。
- 客户端 1 收到此更新,因为 d_1 < d_3.
- 客户端 1 存储 d_3 作为未来的过滤器。
- ...一段时间过去了。
- 客户端 1 应用启动并侦听更新 ≥ d_3。
- 客户端 2 删除城市 2(创建于 d_2)。
- 客户端 1 不会收到此更新,因为 d_2 < d_3.
我的最佳解决方案
不要删除城市,而是添加一个 isDeleted
属性。然后,当一个城市被标记为已删除时,其“lastModified”属性 将更新为“now”。此更新应发送给所有客户端,因为查询过滤器日期始终在“现在”之前。该应用程序的主要业务逻辑忽略了 isDeleted
为 true 的城市。
感觉这个问题我没有完全理解。有没有更好的方法来解决我的问题?
您创建的解决方案非常常见,被称为 tombstone。
由于您不再需要文档的实际数据,您可以删除它的字段。但文档本身需要保留以表明它已被删除。
可能还有其他方法,但它们都会以相似的方式结束。由于您必须以某种方式向每个客户(无论他们何时 connect/query)发出文档已消失的信号,因此将文档保留为墓碑对我来说似乎是一种简单而好的方法。