I want to reduce the number of reads in my firebase application.
I watched this video, but still unsure of how to implement in my project
https://www.youtube.com/watch?v=oDvdAFP6OhQ
There are a couple of posts , but they are 4 or 5 year old answers. my code is not looking similar to that (firebase firestore offline persistence FirebaseError and Cache first implementation for get in firestore )
my index.js (react)
...
import firebase from 'firebase/compat/app';
import 'firebase/compat/analytics';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
import 'firebase/compat/functions';
import 'firebase/compat/storage';
const firebaseConfig = {
apiKey: "-...",
authDomain: ".com",
projectId: "ch",
storageBucket: "grcom",
messagingSenderId: "...",
appId: "1::web:....",
measurementId: "G-...."
};
firebase.initializeApp(firebaseConfig);
firebase.analytics();
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<MtState>
<App />
</MtState>
</React.StrictMode>
);
reportWebVitals();
serviceWorker.unregister();
I have another index.js in functions (firebase functions). This is a folder at the same level as src folder, and contains firebase functions
require("regenerator-runtime/runtime");
const admin = require("firebase-admin");
const builtFunctions = require("./build").default;
admin.initializeApp();
Object.keys(builtFunctions).forEach((functionName) => {
exports[functionName] = builtFunctions[functionName];
});
One of my firebase function, where I want to use cache aka offline data access, or reduce the number of reads
import * as functions from "firebase-functions";
import * as admin from "firebase-admin";
export const getAllProducts = functions.https.onCall(async (data, context) => {
..
const store = admin.firestore();
..
let query = store.collection("products");
const querySnapshot = await query.get();
const items = querySnapshot.docs.map((doc) => ({
...doc.data(),
id: doc.id,
}));
return items;
});
I want to use cache only for certain collections.
How can I enable – enablePersistence() ? Do I need to change query style as below ? My queries can be a little complicated i.e. add conditions dynamically based on UI options, so not sure I can adapt to this style. It is a nightmare.
db.collection("cities").where("state", "==", "CA")
.onSnapshot({ includeMetadataChanges: true }, (snapshot) => {
snapshot.docChanges().forEach((change) => {
if (change.type === "added") {
console.log("New city: ", change.doc.data());
}
var source = snapshot.metadata.fromCache ? "local cache" : "server";
console.log("Data came from " + source);
});
});
Where should I use this code ? what needs to written in place of comments ?
firebase.firestore().enablePersistence()
.catch((err) => {
if (err.code == 'failed-precondition') {
// Multiple tabs open, persistence can only be enabled
// in one tab at a a time.
// ...
} else if (err.code == 'unimplemented') {
// The current browser does not support all of the
// features required to enable persistence
// ...
}
});
// Subsequent queries will use persistence, if it was enabled successfully
When I updated my function like
const store = admin
.firestore()
.enablePersistence()
.catch((err) => {
if (err.code == "failed-precondition") {
console.log(" Multiple tabs open, persistence can only be enabledin one tab at a a time ");
} else if (err.code == "unimplemented") {
console.log("browser cant support");
}
});
I got the error
Object { message: "INTERNAL", status: "INTERNAL" }
see screenshot
2
Answers
The Admin SDKs for Firestore don’t have any built-in persistence mechanism, so your last call (and the approach you’re trying) can’t work.
Also see:
There also is no way to enable caching for only specific collections. Caching on each client is either enabled or it isn’t, and the SDK itself controls what data is cached.
Also see:
If I was in your place, I would use redis to cache it on server.
You can build a microservice deployed on kubernetes 1 OR 2 nodes depending on the replica and resource you are using. Then make a single call to firebase, and cache the data. Rotate cache based on some body/header variable.
In case you want to stick with serverless, you can use redis instance services.
Tanstack-Query would pair very well for caching on client side.