Skip to main content
Version: 2.8.y

Quick Start (Admin) πŸ”₯

note

Composite query or() & and() are only available in web for now because the official admin SDK is lagging behind the official web sdk.

Define The Meta Type​

Meta Type is your single source of truth.

dataType.ts
import { MetaTypeCreator, ServerTimestamp } from 'firelord'

export type Example = MetaTypeCreator<
{
a: number
b: { c: boolean; d: { e: string }[] }
f: { g: ServerTimestamp; h: 1010 | 2929 | 3838 }
}, // can go with even more crazy looking data type
'SomeCollectionName', // collection ID type, must be string literal
string // optional, document ID type, default string
>

Create Firelord References​

init.ts
import { getFirelord, getFirestore } from 'firelord'
import { initializeApp, cert, ServiceAccount } from 'firebase-admin/app' // IMPORTANT: import from 'firebase-admin/app' not 'firebase/admin', the official guide(https://firebase.google.com/docs/firestore/extend-with-functions#data_outside_the_trigger_event) is INCRRECT!
import { Example } from './dataType'

// if you run in cloud function
const app = initializeApp()

// if you run in custom backend
import serviceAccount from './serviceAccount.json' // get it from firebase console --> project setting --> service accounts, THIS IS A SECERT!
const app_ = initializeApp({
credential: cert(serviceAccount as ServiceAccount),
})

export const db = getFirestore(app) // or getFirestore()

export const example = getFirelord<Example>(db, 'SomeCollectionName') // this is your firelordRef

Operations​

operations.ts
import { example } from './init'
import {
getDoc,
setDoc,
updateDoc,
deleteDoc,
addDoc,
serverTimestamp,
increment,
arrayUnion,
} from 'firelord'
//

await createDoc(example.doc('abc'), {
a: 500,
b: { c: true, d: [{ e: 'efg' }] },
f: { g: serverTimestamp(), h: 2929 },
})

await setDoc(example.doc('abc'), {
a: 100,
b: { c: true, d: [{ e: 'abc' }] },
f: { g: serverTimestamp(), h: 1010 },
})

await updateDoc(example.doc('abc'), {
a: increment(1),
'b.d': arrayUnion({ e: 'hello' }), // dot notation form
f: { h: 2929 }, // nested form
})

await deleteDoc(example.doc('abc'))

await getDoc(example.doc('abc')).then(docSnapshot => {
// everything here is narrowly typed based on MetaType
docSnapshot.data() // { a: number; b: { c: boolean; d: { e: string; }[]; }; f: { g: Timestamp | null; h: 1010 | 2929 | 3838; }; | undefined
docSnapshot.exists() // boolean
docSnapshot.get('b.c') // arguments type is "a" | "b.c" | "b.d" | "f.g" | "f.h"
docSnapshot.id // string, based on documentId type

docSnapshot.ref.firestore // firestore instance
docSnapshot.ref.id // same as docSnapshot.id
await docSnapshot.ref.listCollections() // an array of CollectionReference<Example>
docSnapshot.ref.path // full path of this document, type is `SomeCollectionName/${string}`

// ref.parent is recursively typed
// parent of document is collection, parent of collection is document
docSnapshot.ref.parent // in this case, it is collection reference of this document
docSnapshot.ref.parent.firestore // firestore instance
docSnapshot.ref.parent.id // collectionId, type is `SomeCollectionName`
await docSnapshot.ref.parent.listDocuments() // an array of DocumentReference<Any>, NOTE: currently this is not possible to type, you need to type cast it
docSnapshot.ref.parent.parent // no more parent for this case, null
docSnapshot.ref.parent.path // full path of this collection, type is `SomeCollectionName`
})

// in case you want to create auto id doc
await addDoc(example.collection(), {
a: 900,
b: { c: false, d: [{ e: 'hi' }] },
f: { g: serverTimestamp(), h: 3838 },
})
// in case you just want auto id doc ref
const autoIdDocRef = example.doc(example.collection())

Query​

query.ts
import { example } from './init'
import { getDocs, query, where, orderBy, limit } from 'firelordjs'

// filter documents
getDocs(
query(
example.collection(), // or example.collectionGroup()
where('f.h', '>', 1010),
orderBy('f.h'),
limit(10)
)
).then(querySnapshot => {
querySnapshot.docChanges().forEach((docChange, index) => {
docChange.doc // return docSnapshot similar to docSnapshot of getDoc
docChange.type // 'added', 'modified', or 'removed'
docChange.oldIndex // number
docChange.newIndex // number
})
querySnapshot.forEach(docSnapshot => {
// this forEach is not native forEach, it has no index
// similar to docSnapshot of getDoc
})
querySnapshot.docs.forEach((docSnapshot, index) => {
// similar to docSnapshot of getDoc
})
})

// get all collection documents
getDocs(
example.collection() // or example.collectionGroup()
)

OnSnapshot​

onSnapshot.ts
import { example } from './init'
import { query, where, orderBy, onSnapshot, startAfter, offset } from 'firelord'

// listen to filtered collection
const unsub = onSnapshot(
query(
example.collection(), // or example.collectionGroup()
where('b.d', 'array-contains', { e: 'hello' }),
orderBy('f.g'),
startAfter(new Date())
),
querySnapshot => {
// return querySnapshot similar to querySnapshot of getDocs
},
error => {
// handle error
}
)

// listen to entire collection
const unsub2 = onSnapshot(
example.collection(), // or example.collectionGroup()
querySnapshot => {
// return querySnapshot similar to querySnapshot of getDocs
},
error => {
// handle error
}
)

// listen to a single document
const unsub3 = onSnapshot(
example.doc('abc'),
docSnapshot => {
// return docSnapshot similar to docSnapshot of getDoc
},
error => {
// handle error
}
)

// remove listeners
unsub()
unsub2()
unsub3()

Aggregated Count​

aggregatedCount.ts
import { example } from './init'
import { query, where, getCountFromServer } from 'firelordjs'

// get collection aggregated count
getCountFromServer(
example.collection() // also accept example.collectionGroup()
).then(aggregatedQuerySnapshot => {
const count = aggregatedQuerySnapshot.data().count
})

// get query aggregated count
getCountFromServer(
query(
example.collection(), // also accept example.collectionGroup()
where('a', '>', 1)
)
).then(aggregatedQuerySnapshot => {
const count = aggregatedQuerySnapshot.data().count
})

Transaction​

transaction.ts
import { example, db } from './init'
import {
runTransaction,
serverTimestamp,
increment,
arrayRemove,
} from 'firelord'
//

try {
const result = await runTransaction(
db, // db argument is optional, you can skip it
async transaction => {
await transaction.get(example.doc('lmn')).then(docSnapshot => {
const data = docSnapshot.data()
})

transaction.create(example.doc('lmn'), {
a: 500,
b: { c: true, d: [{ e: 'efg' }] },
f: { g: serverTimestamp(), h: 3838 },
})

transaction.set(example.doc('lmn'), {
a: 88,
b: { c: false, d: [{ e: 'opq' }] },
f: { g: serverTimestamp(), h: 2929 },
})

transaction.update(example.doc('lmn'), {
a: increment(1),
b: { d: arrayRemove({ e: 'rst' }) }, // nested form
'f.g': serverTimestamp(), // dot notation form
})

transaction.delete(example.doc('lmn'))

return 123 // return this to result
},
{ readOnly: true, readTime: Timestamp.now() } // optional, { readOnly?: false, maxAttempts?: number } OR { readOnly: true, readTime?: Timestamp }
)
console.log(result) // result is 123 because we return 123 in runTransaction callback
} catch (e) {
console.log('Transaction failed: ', e)
}

Batch​

batch.ts
import { example, db } from './init'
import { writeBatch, serverTimestamp } from 'firelord'

const batch = writeBatch(
db // optional
)

batch.create(example.doc('hij'), {
a: 6,
b: { c: true, d: [{ e: '123' }] },
f: { g: serverTimestamp(), h: 2929 },
})

batch.set(example.doc('hij'), {
a: 7,
b: { c: false, d: [{ e: 'xyz' }] },
f: { g: serverTimestamp(), h: 1010 },
})

batch.update(example.doc('hij'), {
a: 8,
b: { c: false }, // nested form
'f.g': serverTimestamp(), // dot notation form
})

batch.delete(example.doc('hij'))

await batch.commit()