Firebase Firestore Firebase Admin Firestore Adapter - Let's Fix The Confusion
Firebase is a wonderful tool by google to quick setup a remote db with realtime powerful database and other great features! unfortunately poor naming, lack of documentation, and breaking changes from v8 to v9 create a mass of confusion for engineers around the world (and me).
What is what? - terminology
Firebase - application development platform provided by google (not a database! it's application management). in other words "I have lots of applications, i need to manage them)
Firestore - NoSql Database that is also supporting/integrated with firebase and is a standalone database.
firestore-functions(package) - is a package used to perform actions related to cloud functions. or in other words, you'll be using that to react to events and invoke functionality by other firebase features.
firebase/firestore(package) - is meant to be used only with firebase package - and not meant to be used direcrtly.
@next-auth/firebase-adapter - is a common popular firebase adapter for next-auth that lives within nextjs world. essentially it's like @next-auth/mongodb-adapter - it saves the authenticated users (e.g as google provider or any other provider) in firebase.
firebase-admin(package) - The Firebase Admin Node.js SDK enables access to Firebase services from privileged environments (such as servers or cloud) in Node.js.
firebase-admin/app(package) - contains methods that allow us to pick a specific app from our firebase database. or allow us to apply the certificate that we get from the firebase store.
firebase-admin/firestore(package) - contain methods like "getFirestore" that allow us to integrate between firebasse to getFirestore. and it receives whatever app we initialized, picked and certificated from firebase-admin/app (above package).
Why it's called firebase-admin? because you can use this package to interact with firebase from different environments like initializing applications from "google cloud", from "Cloud Functions" or from "your own server" - hence it's called "admin" as it's useful to cross "platforms".
firebase-admin via cloud function:
const { initializeApp, applicationDefault, cert } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
// index.js
initializeApp();
const db = getFirestore();
Initialize on Google Cloud:
const { initializeApp, applicationDefault, cert } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
// index.js:
initializeApp({
credential: applicationDefault()
});
const db = getFirestore();
Initialize on your own server:
const { initializeApp, applicationDefault, cert } = require('firebase-admin/app');
const { getFirestore, Timestamp, FieldValue } = require('firebase-admin/firestore');
// index.js:
const serviceAccount = require('./path/to/serviceAccountKey.json');
initializeApp({
credential: cert(serviceAccount)
});
const db = getFirestore();
The reason it's different initialization from each "environment" is because on your server you might need creditable that from google's servers you don't need(service account, read more here).
Variation in import v8 to v9
// v8
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
// v9
import firebase from 'firebase/compat/app';
import 'firebase/compat/auth';
import 'firebase/compat/firestore';
Which one has collections?
Common error you'll see by typescript:
Property 'collection' does not exist on type 'Firestore'
The reason of the error is that getFirestore from firebase/firestore doesn’t have collection but getFirestore from firebase-admin/firestore does have a collection in its api.
Aggregation Queries (pagination)
for thinks like counting nubmer of documents inside a collection you want to be careful as it can be a price action (e.g if you have 1000 docs each one, while trying to count will be consider as a "read" and you'll be charged)
however in firebase-admin you'll find aggregation queries that will help you to count the number of documents inside a collection - read more.
// will cost your liveliyhood and first born child:
const collectionRef = db.collection('cities');
const snapshot = await collectionRef.count().get(); // each city inside "cities" will count as a "read"
console.log(snapshot.data().count);
// will work fine:
const collectionRef = db.collection('cities');
const query = collectionRef.where('state', '==', 'CA');
const snapshot = await query.count().get();
console.log(snapshot.data().count);
Summary
following this entire journey I think I'll pick MongoDB. Jokes aside, firebase and firestores are strongly useful for realtime data, cloud functions (lamda), and serverless. The pricing of firestore is more "clear" (per X reads/write/deletion) but has less flexibility than mongo (you can set the server wherever you want).