长话短说:博士;
不幸的是,这是当前捆绑包编码方式的限制。它也超出了 bundle 的范围,因为它们被设计用于针对具有大量重用数据的集合以用于页面的初始加载。
如果您认为 loadBundle 应该从本地缓存中清除未在捆绑包中返回的项目,您应该 file a feature request 将此功能添加到 loadBundle 调用(例如 loadBundle(rawBundle, /* forceRefresh = */ true))或 file a bug report。
细节
例如,假设您的查询是“获取集合/Posts 中的前 10 个帖子”。
请求此查询的包后,第一个包返回以下结果:
{
"/Posts/D9p7MbcYCbTNzcXLrzfQ": { /* post data */ },
"/Posts/xz3eY1Gwsjl4tTxTjXyR": { /* post data */ },
"/Posts/fIvk5LF2zj2xgpgWIv9h": { /* post data */ }
}
然后你使用loadBundle加载它。
接下来,使用另一个客户端从服务器中删除其中两个文档(使用同一个客户端会将它们从本地缓存中删除)。
现在您重新请求包,它返回:
{
"/Posts/fIvk5LF2zj2xgpgWIv9h": { /* post data */ }
}
在调用loadBundle 时,库遍历包中的文档集合,更新每个文档的本地缓存:
// this is psuedo-code, not the true implementation
function loadBundle(rawBundle) {
decodedBundle = parseBundle(rawBundle);
decodedBundle.docs.forEach((doc) => {
cachedDocuments.set(doc.id, doc);
})
return { // return bundle load progress
totalDocuments: decodedBundle.docs.length,
/* ... other stats ... */
};
}
在上面的伪代码中,您可以看到只有包含在捆绑包中的文档才会在本地缓存中更新。未包含在包中的文档不会更新,并且返回的统计信息与包中包含的刚刚解码的文档相关 - 而不是相关查询的结果。
当您运行命名查询时,查询将针对本地缓存进行解码、比较和执行。由于以前的文档当前根据缓存匹配查询,因此它们包含在结果中。
只有在以下情况下,才会省略本地缓存中的文档:
- 解码查询返回10个以上的结果,不符合查询条件。
- 查询是针对实时数据库执行的。
- 如果下载的包包含元数据,表明文档已被删除。
因此,要清除本地缓存,捆绑包必须包含:
{
"/Posts/D9p7MbcYCbTNzcXLrzfQ": _DELETED,
"/Posts/xz3eY1Gwsjl4tTxTjXyR": _DELETED,
// ... for every deleted document that ever existed ...
"/Posts/fIvk5LF2zj2xgpgWIv9h": { /* post data */ }
}
返回这样的捆绑包在技术上很复杂,而且效率极低。
请求捆绑包时,您可以包括文档 ID 列表,如果给定的文档 ID 不存在,则文档删除将包含在包的数据中。但是,在这样做时,您也可以使用getDocs 或onSnapshot 向服务器发出一个普通的数据库请求以获得相同的结果,这样会更快、更便宜。
Bundle 旨在用于具有大量重用数据的集合,并且通常仅在页面的初始加载时使用。如果前 50 个结果中的帖子被删除,您将使缓存的结果无效并重建包。所有新用户都会立即看到更改后的结果,只有那些拥有本地副本的用户才能看到它们。
如果您认为 loadBundle 应该从本地缓存中清除未在捆绑包中返回的项目,您应该 file a feature request 将此功能添加到 loadBundle 调用(例如 loadBundle(rawBundle, /* forceRefresh = */ true))。