Kotlin: Firestore-compatible API
Firebase-style collection, document and query references on top of Sovaria documents, for moving a Firebase app over with the Kotlin SDK.
Firebase-style collection, document and query references on top of Sovaria documents, for moving a Firebase app over. Every call runs as the client's signed-in user, so your project's policies and row-level security apply. Types and members are listed in source order; each one links to its HTTP endpoint where it maps to one.
#Types and members
FirebaseFirestore
The Firebase Android SDK's Firestore API on Sovaria documents: move an app by changing imports (com.google.firebase.firestore.* → in.sovaria.firestore.*) and how db is made.
Names, arguments and shapes follow Firebase (data, exists(), documentChanges, ListenerRegistration, SetOptions.merge(), snapshots() flows as in the KTX library). Operations are suspend functions instead of Tasks. Underneath it is the Sovaria collection API, so collection rules and row policies decide every read and write. Timestamps are stored as ISO-8601 strings (Timestamp and Date values you write are converted; Timestamp.parse reads one back), and there is no offline document cache.
class FirebaseFirestore private constructor(val sovaria: Sovaria)FirebaseFirestore.getInstance
The Firestore handle for a Sovaria client (one per client).
fun getInstance(sovaria: Sovaria): FirebaseFirestoreFirebaseFirestore.collection
collection("users") or collection("users/$uid/posts").
fun collection(collectionPath: String): CollectionReferenceFirebaseFirestore.document
document("users/$uid").
fun document(documentPath: String): DocumentReferenceFirebaseFirestore.collectionGroup
Every collection with this id at any depth (comments, posts/p1/comments, …).
fun collectionGroup(collectionId: String): QueryFirebaseFirestore.batch
fun batch(): WriteBatchFirebaseFirestore.runTransaction
Run function and commit its writes atomically; retried (up to maxAttempts) when a document it read changed meanwhile.
suspend fun <T> runTransaction(maxAttempts: Int = 5, function: suspend (Transaction) -> T): TUnlike Firebase's Transaction.Function, it is a suspend lambda (reads go to the server).
Timestamp
A point in time. Stored as an ISO-8601 string in Sovaria.
data class Timestamp(val seconds: Long, val nanoseconds: Int) : Comparable<Timestamp>Timestamp.Timestamp.init
Create an instance.
constructor(date: Date) : this(Math.floorDiv(date.time, 1000L), (Math.floorMod(date.time, 1000L) * 1_000_000).toInt())Timestamp.toDate
fun toDate(): DateTimestamp.toInstant
fun toInstant(): InstantTimestamp.toIso
2026-01-02T03:04:05.000Z (milliseconds, UTC).
fun toIso(): StringTimestamp.compareTo
override fun compareTo(other: Timestamp)Timestamp.now
fun now(): TimestampTimestamp.parse
Read back a stored timestamp (an ISO string).
fun parse(iso: String): TimestampVectorValue
A vector value (FieldValue.vector(...)); stored as an array of numbers.
data class VectorValue(val values: DoubleArray)VectorValue.toArray
fun toArray(): DoubleArrayVectorValue.equals
override fun equals(other: Any?)VectorValue.hashCode
override fun hashCode()FieldPath
A field path: FieldPath.of("address", "city"), or FieldPath.documentId() to filter or order by the id.
class FieldPath private constructor(val segments: List<String>)FieldPath.of
fun of(vararg fieldNames: String)FieldPath.documentId
fun documentId()FieldPath.equals
override fun equals(other: Any?)FieldPath.hashCode
override fun hashCode()FieldPath.toString
override fun toString()FieldValue
Atomic field updates, applied by the server inside the commit.
class FieldValue private constructor(internal val op: String, internal val value: Any? = null)FieldValue.delete
fun delete()FieldValue.serverTimestamp
fun serverTimestamp()FieldValue.arrayUnion
fun arrayUnion(vararg elements: Any?)FieldValue.arrayRemove
fun arrayRemove(vararg elements: Any?)FieldValue.increment
fun increment(l: Long)FieldValue.increment
fun increment(d: Double)FieldValue.increment
fun increment(i: Int)FieldValue.vector
fun vector(values: DoubleArray)SetOptions
SetOptions.merge() or SetOptions.mergeFields("a", "b.c").
class SetOptions private constructor(internal val merge: Boolean, internal val fields: List<String>?)SetOptions.merge
fun merge()SetOptions.mergeFields
fun mergeFields(vararg fields: String)SetOptions.mergeFieldPaths
fun mergeFieldPaths(fields: List<FieldPath>)DocumentReference
class DocumentReference internal constructor(val firestore: FirebaseFirestore, val path: String)DocumentReference.id
A property.
val id: String get()DocumentReference.parent
A property.
val parent: CollectionReference get()DocumentReference.collection
fun collection(collectionPath: String)DocumentReference.get
suspend fun get(): DocumentSnapshotDocumentReference.set
Replace the document, or merge into it with SetOptions.merge().
suspend fun set(data: Map<String, Any?>, options: SetOptions? = null)DocumentReference.update
Change fields ("a.b" dotted paths and FieldPath keys allowed); fails with 404 when it doesn't exist.
suspend fun update(data: Map<String, Any?>)DocumentReference.update
suspend fun update(field: String, value: Any?, vararg moreFieldsAndValues: Any?)DocumentReference.update
suspend fun update(field: FieldPath, value: Any?, vararg moreFieldsAndValues: Any?)DocumentReference.delete
suspend fun delete()DocumentReference.addSnapshotListener
The document now and after every change.
fun addSnapshotListener(listener: EventListener<DocumentSnapshot>): ListenerRegistrationremove() stops it.
DocumentReference.addSnapshotListener
fun addSnapshotListener(executor: Executor?, listener: EventListener<DocumentSnapshot>): ListenerRegistrationDocumentReference.snapshots
KTX: the document as a Flow.
fun snapshots(): Flow<DocumentSnapshot>DocumentReference.equals
override fun equals(other: Any?)DocumentReference.hashCode
override fun hashCode()DocumentReference.toString
override fun toString()Filter
One filter or an or / and group: where(Filter.or(Filter.equalTo("a", 1), Filter.lessThan("b", 2))).
class Filter private constructor(internal val wire: Any)Filter.equalTo
fun equalTo(field: Any, value: Any?)Filter.notEqualTo
fun notEqualTo(field: Any, value: Any?)Filter.lessThan
fun lessThan(field: Any, value: Any)Filter.lessThanOrEqualTo
fun lessThanOrEqualTo(field: Any, value: Any)Filter.greaterThan
fun greaterThan(field: Any, value: Any)Filter.greaterThanOrEqualTo
fun greaterThanOrEqualTo(field: Any, value: Any)Filter.arrayContains
fun arrayContains(field: Any, value: Any)Filter.arrayContainsAny
fun arrayContainsAny(field: Any, values: List<Any?>)Filter.inArray
fun inArray(field: Any, values: List<Any?>)Filter.notInArray
fun notInArray(field: Any, values: List<Any?>)Filter.or
Documents matching any of the filters (at most 30 OR terms after expansion).
fun or(vararg filters: Filter)Filter.and
Documents matching all of the filters, for nesting inside or.
fun and(vararg filters: Filter)Query
open class Query internal constructor(
val firestore: FirebaseFirestore,
/** The collection path (a collection id for a collection group). */
val path: String,
internal val body: Map<String, Any?>,
internal val isGroup: Boolean = false,
)Query.parameters
The request body (for tests and debugging).
val parameters: Map<String, Any?> get()Query.where
fun where(filter: Filter): QueryQuery.whereEqualTo
fun whereEqualTo(field: String, value: Any?)Query.whereEqualTo
fun whereEqualTo(field: FieldPath, value: Any?)Query.whereNotEqualTo
fun whereNotEqualTo(field: String, value: Any?)Query.whereNotEqualTo
fun whereNotEqualTo(field: FieldPath, value: Any?)Query.whereLessThan
fun whereLessThan(field: String, value: Any)Query.whereLessThan
fun whereLessThan(field: FieldPath, value: Any)Query.whereLessThanOrEqualTo
fun whereLessThanOrEqualTo(field: String, value: Any)Query.whereLessThanOrEqualTo
fun whereLessThanOrEqualTo(field: FieldPath, value: Any)Query.whereGreaterThan
fun whereGreaterThan(field: String, value: Any)Query.whereGreaterThan
fun whereGreaterThan(field: FieldPath, value: Any)Query.whereGreaterThanOrEqualTo
fun whereGreaterThanOrEqualTo(field: String, value: Any)Query.whereGreaterThanOrEqualTo
fun whereGreaterThanOrEqualTo(field: FieldPath, value: Any)Query.whereArrayContains
fun whereArrayContains(field: String, value: Any)Query.whereArrayContains
fun whereArrayContains(field: FieldPath, value: Any)Query.whereArrayContainsAny
fun whereArrayContainsAny(field: String, values: List<Any?>)Query.whereArrayContainsAny
fun whereArrayContainsAny(field: FieldPath, values: List<Any?>)Query.whereIn
fun whereIn(field: String, values: List<Any?>)Query.whereIn
fun whereIn(field: FieldPath, values: List<Any?>)Query.whereNotIn
fun whereNotIn(field: String, values: List<Any?>)Query.whereNotIn
fun whereNotIn(field: FieldPath, values: List<Any?>)Query.orderBy
fun orderBy(field: String, direction: Direction = Direction.ASCENDING)Query.orderBy
fun orderBy(field: FieldPath, direction: Direction = Direction.ASCENDING)Query.limit
fun limit(limit: Long)Query.limitToLast
fun limitToLast(limit: Long)Query.startAt
fun startAt(vararg fieldValues: Any?)Query.startAfter
fun startAfter(vararg fieldValues: Any?)Query.endAt
fun endAt(vararg fieldValues: Any?)Query.endBefore
fun endBefore(vararg fieldValues: Any?)Query.startAt
fun startAt(snapshot: DocumentSnapshot)Query.startAfter
fun startAfter(snapshot: DocumentSnapshot)Query.endAt
fun endAt(snapshot: DocumentSnapshot)Query.endBefore
fun endBefore(snapshot: DocumentSnapshot)Query.get
suspend fun get(): QuerySnapshotQuery.addSnapshotListener
Live results: the listener runs with the first snapshot and after every change.
fun addSnapshotListener(listener: EventListener<QuerySnapshot>): ListenerRegistrationremove() stops it.
Query.addSnapshotListener
As above, calling listener on executor (e.g.
fun addSnapshotListener(executor: Executor?, listener: EventListener<QuerySnapshot>): ListenerRegistrationContextCompat.getMainExecutor(context)).
Query.snapshots
KTX: the live results as a Flow.
fun snapshots(): Flow<QuerySnapshot>Query.count
count().get(AggregateSource.SERVER).count.
fun count()Query.aggregate
aggregate(AggregateField.count(), AggregateField.sum("price")).get(AggregateSource.SERVER).
fun aggregate(field: AggregateField, vararg fields: AggregateField)Query.findNearest
Vector search: this query's filters first, then the limit documents whose vectorField is closest.
fun findNearest(
vectorField: Any,
queryVector: VectorValue,
limit: Int,
distanceMeasure: DistanceMeasure,
distanceResultField: String? = null,
distanceThreshold: Double? = null,
): VectorQueryDirection
enum class DirectionCollectionReference
class CollectionReference internal constructor(firestore: FirebaseFirestore, path: String) : Query(firestore, path, emptyMap())CollectionReference.id
A property.
val id: String get()CollectionReference.parent
The document this subcollection belongs to, or null for a top-level collection.
val parent: DocumentReference? get()CollectionReference.document
A new document with a random id.
fun document(): DocumentReferenceCollectionReference.document
fun document(documentPath: String): DocumentReferenceCollectionReference.add
Create a document with a new id.
suspend fun add(data: Map<String, Any?>): DocumentReferenceDistanceMeasure
enum class DistanceMeasure(internal val wire: String)VectorQuery
class VectorQuery internal constructor(private val query: Query, private val body: Map<String, Any?>)VectorQuery.get
suspend fun get(): QuerySnapshotAggregateField
class AggregateField private constructor(internal val op: String, internal val fieldName: String?)AggregateField.equals
override fun equals(other: Any?)AggregateField.hashCode
override fun hashCode()AggregateField.count
fun count()AggregateField.sum
fun sum(field: String)AggregateField.sum
fun sum(field: FieldPath)AggregateField.average
fun average(field: String)AggregateField.average
fun average(field: FieldPath)AggregateSource
enum class AggregateSourceAggregateQuery
class AggregateQuery internal constructor(val query: Query, private val fields: List<AggregateField>)AggregateQuery.get
suspend fun get(source: AggregateSource = AggregateSource.SERVER): AggregateQuerySnapshotAggregateQuerySnapshot
class AggregateQuerySnapshot internal constructor(private val values: Map<String, Any?>)AggregateQuerySnapshot.count
A property.
val count: Long get()AggregateQuerySnapshot.get
The value for field (a Number, or null when there was nothing to average).
fun get(field: AggregateField): Number?AggregateQuerySnapshot.getDouble
fun getDouble(field: AggregateField): Double?AggregateQuerySnapshot.getLong
fun getLong(field: AggregateField): Long?SnapshotMetadata
data class SnapshotMetadata(private val pendingWrites: Boolean, val isFromCache: Boolean)SnapshotMetadata.hasPendingWrites
fun hasPendingWrites()DocumentSnapshot
open class DocumentSnapshot internal constructor(val reference: DocumentReference, internal val raw: RawDoc)DocumentSnapshot.id
A property.
val id: String get()DocumentSnapshot.exists
fun exists(): BooleanDocumentSnapshot.metadata
A property.
val metadata: SnapshotMetadata get()DocumentSnapshot.data
The data, or null when the document doesn't exist.
open val data: Map<String, Any?>? get()DocumentSnapshot.get
A field by dotted path (get("address.city")) or FieldPath; null when missing.
fun get(field: String): Any?DocumentSnapshot.get
fun get(field: FieldPath): Any?DocumentSnapshot.contains
Whether the field exists (it may hold null).
fun contains(field: String): BooleanDocumentSnapshot.getString
fun getString(field: String)DocumentSnapshot.getLong
fun getLong(field: String)DocumentSnapshot.getDouble
fun getDouble(field: String)DocumentSnapshot.getBoolean
fun getBoolean(field: String)DocumentSnapshot.getTimestamp
A stored ISO-8601 timestamp as a Timestamp.
fun getTimestamp(field: String)DocumentSnapshot.getDate
fun getDate(field: String)QueryDocumentSnapshot
class QueryDocumentSnapshot internal constructor(reference: DocumentReference, raw: RawDoc) : DocumentSnapshot(reference, raw)QueryDocumentSnapshot.data
A property.
override val data: Map<String, Any?> get()DocumentChange
class DocumentChange internal constructor(val type: Type, val document: QueryDocumentSnapshot, val oldIndex: Int, val newIndex: Int)Type
enum class TypeQuerySnapshot
class QuerySnapshot internal constructor(val query: Query, docs: List<RawDoc>, changes: List<Change>) : Iterable<QueryDocumentSnapshot>QuerySnapshot.documents
A property.
val documents: List<QueryDocumentSnapshot>QuerySnapshot.documentChanges
A property.
val documentChanges: List<DocumentChange>QuerySnapshot.size
fun size()QuerySnapshot.isEmpty
A property.
val isEmpty: Boolean get()QuerySnapshot.metadata
A property.
val metadata: SnapshotMetadataQuerySnapshot.iterator
override fun iterator()WriteBatch
Writes committed together: every one or none.
class WriteBatch internal constructor(private val firestore: FirebaseFirestore)WriteBatch.set
fun set(documentRef: DocumentReference, data: Map<String, Any?>, options: SetOptions? = null)WriteBatch.update
fun update(documentRef: DocumentReference, data: Map<String, Any?>)WriteBatch.update
fun update(documentRef: DocumentReference, field: String, value: Any?, vararg moreFieldsAndValues: Any?)WriteBatch.delete
fun delete(documentRef: DocumentReference)WriteBatch.commit
suspend fun commit()Transaction
Read every document first, then write; the commit fails (and is retried) if a read document changed.
class Transaction internal constructor(private val firestore: FirebaseFirestore)Transaction.get
suspend fun get(documentRef: DocumentReference): DocumentSnapshotTransaction.set
fun set(documentRef: DocumentReference, data: Map<String, Any?>, options: SetOptions? = null)Transaction.update
fun update(documentRef: DocumentReference, data: Map<String, Any?>)Transaction.update
fun update(documentRef: DocumentReference, field: String, value: Any?, vararg moreFieldsAndValues: Any?)Transaction.delete
fun delete(documentRef: DocumentReference)interface
fun interface EventListener<T>missing
fun missing(path: String)interface
fun interface ListenerRegistrationgroupPollMs
A server without collection-group listeners (older): the group query is re-run this often.
@Volatile var groupPollMs