Advanced Usage
Once you’ve mastered basic CRUD, decorators, relations and hooks, explore these advanced Firestore features with FireODM.
1. Custom Converters
Sometimes you need to transform fields on the fly (e.g., encrypting, custom class instances). FireODM lets you register a FirestoreDataConverter:
import { FirestoreDataConverter, QueryDocumentSnapshot } from 'firebase-admin/firestore'
import { getFirestoreInstance } from 'fireodm/config'
import { BaseModel } from 'fireodm'
// Define converter
const MyConverter: FirestoreDataConverter<MyClass> = {
toFirestore(inst) {
return { raw: inst.toJSON() }
},
fromFirestore(snapshot: QueryDocumentSnapshot) {
const data = snapshot.data()
return new MyClass(data.raw)
}
}
// Apply converter manually if needed
const col = getFirestoreInstance()
.collection('mycol')
.withConverter(MyConverter)
2. Pagination & Cursors
Use findAll
options to page through large datasets:
const page1 = await User.findAll({ limit: 10, orderBy: { field: 'createdAt', direction: 'asc' } })
const cursor = page1.lastVisible
const page2 = await User.findAll({
limit: 10,
orderBy: { field: 'createdAt', direction: 'asc' },
startAfter: cursor
})
Fields must be indexed in Firestore for composite queries.
3. Select & Projection
Fetch only specific fields to reduce bandwidth:
const { results } = await User.findAll({
queryFn: ref => ref.select('name','email'),
})
// Each User instance will only have 'name' and 'email' populated
4. Complex Queries
Combine where
, in
, array-contains
, etc.:
// users whose role is one of ['admin','editor']
const users = await User.findWhere('role','in',['admin','editor'])
// posts tagged with 'news'
const newsPosts = await Post.findWhere('tags','array-contains','news')
5. GeoPoints & Timestamps
Decorate GeoPoint
and Timestamp
fields:
import { GeoPointField, TimestampField } from 'fireodm'
import { GeoPoint } from 'firebase-admin/firestore'
class Place extends BaseModel {
@GeoPointField()
location!: GeoPoint
@TimestampField({ defaultNow: true })
visitedAt?: Timestamp
}
// Query by bounding box
const nearby = await Place.findAll({
queryFn: ref => ref
.where('location', '>=', new GeoPoint(lat1, lng1))
.where('location', '<=', new GeoPoint(lat2, lng2))
})
6. Transactions & Batches (Recap)
Refer back to the Transactions & Batched Writes guide for atomic multi-op patterns.
Next: FAQ & Troubleshooting for common issues and best practices.