useMongocampAggregation
Aggregation, distinct values and sampling over collectionApi.aggregate / distinct, with timeouts, defensive result handling and readable errors. It is the engine behind MongocampAggregationBuilder, the value suggestions in MongocampFilterBuilder and the field statistics in MongocampCollectionInfos, and works in session and server proxy mode alike (it calls useMongocampClientApi).
const { runAggregation, listDistinct, sampleDocuments, describeAggregationError } = useMongocampAggregation()
const { rows, total, pages, page } = await runAggregation('customers', [
{ stage: '$group', value: { _id: '$country', n: { $sum: 1 } } },
{ stage: '$sort', value: { n: -1 } },
], { page: 1, rowsPerPage: 20 })runAggregation(collection, pipeline, { page, rowsPerPage })
pipeline is { stage: '$match', value: <JSON> }[] — value is real JSON (a number for $limit, an object for most stages), not a string. Returns:
{ rows: Record<string, unknown>[], total: number, pages: number, page: number }total, pages and page come from the server's x-pagination-* headers (falling back to the row count, 1 and the requested page); rowsPerPage defaults to the server's 100. Entries that are not objects are dropped. The request has a 30 s timeout and always sends allowDiskUse: false (the server requires the field).
- Refuses forbidden pipelines. Before any request, a pipeline using
$out,$merge,$function,$accumulator,$where,$lookup,$unionWithor$graphLookup— as a stage or nested at any depth — is rejected with aForbiddenPipelineError(.findingslists operator, stage and path). The server does not restrict stages itself. - An empty result is an empty page. The server answers an aggregation with no documents at all with
500 "Index 0 out of bounds for length 0"(on existing collections too).runAggregationturns exactly that error into{ rows: [], total: 0, pages: 0, page }. Any other error rejects with the original error.
listDistinct(collection, field, limit = 100)
Distinct values of a field: { values, total, truncated }. Only strings, numbers and booleans are returned — null (which is what the server answers for a field nobody has), arrays (not unwound) and objects are dropped. The values are in no particular order. truncated is true when the field has more distinct values than limit. 15 s timeout.
sampleDocuments(collection, size = 500)
A random sample in one page — an aggregation with $sample, size clamped to 1–1 000. Same result shape as runAggregation. This is how the field statistics are computed: the server's own getSchemaAnalysis is not used because (1.5.10) it returns an accumulation of every analysis since the server started, across collections — a cross-collection information leak that also grows with every call.
describeAggregationError(error)
Async, because the server explains a failure in the response body. Returns { kind, message }:
kind | When |
|---|---|
forbidden | a ForbiddenPipelineError; the message names the operator |
retryable | an unexpected 405 (an intermittent proxy response) |
mongo | MongoDB rejected a command; message is only MongoDB's own text |
network / unauthorized / forbidden-access / other | the shared mapping of useMongocampError |
The server's raw error contains the address of the database server (… on server host:port. …); it is removed from every message this returns.
What the server does that you might not expect
Verified against MongoCamp 1.5.10:
- results are plain JSON: dates as ISO strings without milliseconds,
_idas a hex string, 64-bit integers as bare numbers (rounded beyond 2^53); distinctanswers with native values although the generated client types it asstring[];- the generated client types a stage's
valueasstring; the server wants JSON (the composable casts).
Related
MongocampAggregationBuilderuseMongocampQuery— Lucene filters for the document list; aggregation$matchuses MongoDB query syntax instead