$query
The $query utility allows you to query multiple documents from a Firestore collection reactively and locally cache their data using IndexedDB via @vueuse/integrations. This is part of the arkfire ecosystem and works alongside $pool and listeners to provide seamless, deduplicated reactive data arrays in sync with firestore.
Purpose
To query a Firestore collection with constraints, cache the results locally, and return a live-updating deduplicated array of document data.
Api
Ref may only be used in a component lifecycle to avoid memory leaks.
const users = $query("users", [where("active", "==", true)])users is a computed ref that will automatically:
- Fetch initial query results from Firestore
- Cache those results locally in IndexedDB
- Reactively update whenever the underlying documents change
Parameters
colId: string
A string representing the collection ID in Firestore.
query: QueryConstraint[]
An array of Firestore query constraints (e.g. where, orderBy, etc).
All firebase functions are passed through (e.g.
documentId(),deleteField(), etc).
Returns
ComputedRef<any[]>
An automatically deduplicated, reactive list of the resulting document data. This is readonly. To update use $col or $doc to update firestore directly.
How It Works
Generate a stable cache key: Uses
$pool.serializeQueryKeyto turn the query and collection ID into a unique key.Initial fetch and state tracking: Uses
computedAsyncto fetch uncached data and populate theuseStatearray for the query.Listen to changes:
$pool.listenToCollectionis used to setup reactive subscriptions on document updates.Local cache setup per document: Each document path is mapped to an
useIDBKeyvalhook to cache and reactively update individual entries.Automatic deduplication: Uses
Setto ensure unique paths only.Live list: A
computedref returns the list of document data by pulling.datafrom each IDB-backed ref.
Dev Notes
- Server-side execution returns an empty array immediately.
- Uses Nuxt's
useState()to persist query results across components. listenersis responsible for wiring up reactive streams to Firestore listeners and IndexedDB updates.
Example
const posts = $query("posts", [where("published", "==", true), orderBy("createdAt", "desc")])
watchEffect(() => {
console.log(posts.value) // in sync with firestore
})You can also listen to non existant document that will be picked up when created. This still counts as a document read.
Related Utilities
$poollistenersuseIDBKeyval(from@vueuse/integrations)
Benefits
- ✅ Deduplicated query results
- ✅ Local IndexedDB caching for offline use
- ✅ Reactive updates using Firestore listeners
- ✅ Seamless integration with Nuxt state and Vue
This utility abstracts the complexity of merging Firestore streams and caching into a single powerful hook.