Skip to content
Bluetape4k docs1.11

Coroutine reads and cardinality

Latest stable Based on Bluetape4k release 1.11.0

findAsFlow<T>(query) and findAllAsFlow<T>() call asFlow() on Spring Data publishers. Calling the extension does not immediately load a list. Subscription begins when a consumer collects the Flow.

fun findAdults(city: String): Flow<User> {
val query = queryOf(
"age".criteria() gte 20,
"city".criteria() eq city,
).sortAscBy("name")
return mongoOperations.findAsFlow(query)
}

Zero documents produces an empty Flow. Collecting the same Flow again can create another subscription and query.

Expected resultAPIZero documents
Absence is validfindOneOrNullSuspending<T>, findByIdOrNullSuspending<T>null
A document is requiredfindOneSuspending<T>, findByIdSuspending<T>NoSuchElementException

The two families use awaitSingleOrNull() and awaitSingle(), respectively. Neither turns a connection or mapping failure into null.

suspend fun requireUser(id: String): User =
mongoOperations.findByIdSuspending(id)
suspend fun findUser(id: String): User? =
mongoOperations.findByIdOrNullSuspending(id)

Attach domain meaning such as HTTP 404 outside the repository. Mapping every driver failure to 404 would hide an outage as missing data.

countSuspending<T>(query) returns Long; existsSuspending<T>(query) returns Boolean. Use exists instead of reading a document list when only presence matters.

suspend fun emailExists(email: String): Boolean =
mongoOperations.existsSuspending<User>(
queryOf("email".criteria() eq email)
)

No match returns 0L or false, not a failure.

Cancelling Flow collection is propagated to the reactive subscription. Do not catch it and emit normal data. For large results, add an explicit order and limit, and observe consumer throughput together with pool usage.

Writes and atomic operations separates write results and atomicity boundaries.