Я создал пакет из 3 документов. Затем я удалил 2 из них и снова создал пакет. Итак, в комплекте теперь один документ! А кеш приложений содержит 3
Затем я снова загружаю пакет:
const resp = await fetch(downloadUrl);
await loadBundle(db, resp.body); //{totalDocuments: 1} - as expected
const query = await namedQuery(db, `my-bundle-query`);
if (query) {
const snap = await getDocsFromCache(query); //Nope! there should be one document, but there are three
}
Похоже на ошибку. Я думаю, что loadBundle должен каким-то образом отслеживать удаленные документы. Что я должен делать?
ОБНОВЛЯТЬ:
namedQuery — запросить весь кеш. Но ожидаемое поведение — получить только документы, связанные с пакетом. Так что это вообще не работает - в моем namedQuery у меня есть ограничение в 4 документа, но из кеша я получил больше!!
Так что официальный пример неверен, потому что он сталкивается с той же проблемой, которую я описал выше.
К сожалению, это ограничение способа кодирования пакетов в настоящее время. Это также не подходит для пакетов, поскольку они предназначены для использования против коллекций с большим объемом повторно используемых данных для начальной загрузки страницы.
Если вы считаете, что loadBundle
следует удалять элементы из локального кеша, которые не возвращаются в пакете, вам следует отправить запрос функции , чтобы добавить эту функцию в вызов loadBundle
(например, loadBundle(rawBundle, /* forceRefresh = */ true)
) или отправить отчет об ошибке .
Например, предположим, что ваш запрос — «Получить первые 10 сообщений в коллекции /Posts».
При запросе пакета для этого запроса первый пакет возвращает следующие результаты:
{
"/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 ... */
};
}
В приведенном выше псевдокоде видно, что в локальном кеше обновляются только те документы, которые включены в бандл. Документы, не включенные в пакет, не обновляются, а возвращаемая статистика относится к документам, включенным в только что декодированный пакет, а не к результатам соответствующего запроса.
Когда вы запускаете именованный запрос, он декодируется, сравнивается и выполняется с локальным кешем. Поскольку прежние документы в настоящее время соответствуют запросу в соответствии с кешем, они включаются в результаты.
Документы в локальном кеше будут пропущены только в следующих случаях:
Таким образом, для очистки локального кеша пакет должен содержать:
{
"/Posts/D9p7MbcYCbTNzcXLrzfQ": _DELETED,
"/Posts/xz3eY1Gwsjl4tTxTjXyR": _DELETED,
// ... for every deleted document that ever existed ...
"/Posts/fIvk5LF2zj2xgpgWIv9h": { /* post data */ }
}
Возврат такого пакета был бы технически сложным и невероятно неэффективным.
При запросе пакета вы можете включить список идентификаторов документов, где, если данный идентификатор документа не существует, удаление документа включается в данные пакета. Однако при этом вы можете просто сделать обычный запрос к базе данных на сервер, используя getDocs
или onSnapshot
для того же результата, что будет быстрее и дешевле.
Пакеты предназначены для использования против коллекций с большим объемом повторно используемых данных и, как правило, только при начальной загрузке страницы. Если сообщение будет удалено из 50 лучших результатов, вы аннулируете кешированные результаты и перестроите пакет. Все новые пользователи сразу увидят измененные результаты, и только те пользователи, у которых есть локальная копия, увидят их.
Если вы считаете, что loadBundle
следует удалять элементы из локального кеша, которые не возвращаются в пакете, вам следует отправить запрос функции, чтобы добавить эту функцию в вызов loadBundle
(например, loadBundle(rawBundle, /* forceRefresh = */ true)
).
@ValeraKvip, если у вас есть 50 документов в комплекте, но два недавно были удалены, вы получите только 2 чтения после загрузки их в кеш с помощью getDocsFromCache
, а затем получения последней версии с помощью getDocs
/onSnapshot
. Это по-прежнему экономит 48 операций чтения на пользователя.
почему? Как узнать, какие документы были удалены, не запрашивая их все? Согласен с вами, что бандл ничего не должен знать о своих предыдущих версиях и удалять документ. А вот то, что namedQuery не относится к бандлу (читает все документы в кеше) или какой-то другой метод, который бы читал только документы из бандла — это проблема.
@ValeraKvip Когда вы прикрепляете прослушиватель к местоположению Firestore, SDK сообщает имена документов, которые удовлетворяют запросу сервера. Затем SDK сравнивает свои кэшированные документы с именами и запрашивает у сервера любые документы, для которых у него еще нет данных. Каждый новый документ подвергается чтению, когда вы загружаете его содержимое, в то время как запрос результатов индекса не выполняется.
Не могли бы вы предоставить ссылку, чтобы доказать это поведение? Кроме того, удаленный документ будет стоить одно чтение для КАЖДОГО клиента! Как будто каждое изменение будет стоить чтения для КАЖДОГО клиента, и я просто хотел избежать этого с помощью пакетов.
@ValeraKvip Вот исходный код API-метода loadBundle и его реализация , а также логика обновления кэшированных результатов.
@ValeraKvip Если вместо этого вы имели в виду ссылки, подтверждающие поведение биллинга чтения/записи, документация по выставлению счетов по прослушиванию запросов охватывает это.
Я не совсем правильно задал этот вопрос, я задал другой, более правильный. Но вы дали отличный хорошо описанный ответ, спасибо. принимаю как ответ.
Так что официальный пример - ложь firebase.google.com/docs/firestore/bundles Потому что в их примере, если вы удалите документ, он останется в кеше. Это также нарушает логику именованных запросов, поскольку они не связаны с документами в пакете, а просто выполняются над кешем. Поэтому все обещания, что вместо прочтения 50 документов можно составить из них пачку и прочитать один раз - вранье, потому что нужно читать те же 50 документов, чтобы отслеживать удаления документов - это провал планетарного масштаба. Спасибо за ответ!