Documentation
¶
Index ¶
- Constants
- Variables
- func Accumulators() []string
- func CutSink(p Pipeline) (StageSpec, Pipeline)
- func ExplainStages(p Pipeline) string
- func HasLookup(p Pipeline) bool
- func SinkName(s StageSpec) string
- func SplitPrefix(p Pipeline) (Prefix, Pipeline)
- func Stages() []string
- type AbsExpr
- type AccumOp
- type AccumSpec
- type Accumulator
- type AddFieldsSpec
- type AddFieldsStage
- type ArithExpr
- type ArithOp
- type ArrayExpr
- type CompareExpr
- type CompareOp
- type ConcatExpr
- type CondExpr
- type CountSpec
- type CountStage
- type Ctx
- type DateAddExpr
- type DateDiffExpr
- type DatePartExpr
- type DateTruncExpr
- type Env
- type Expr
- type FacetSpec
- type FacetStage
- type FieldRefExpr
- type GroupSpec
- type GroupStage
- type IfNullExpr
- type LimitSpec
- type LimitStage
- type Limits
- type LiteralExpr
- type LookupFunc
- type LookupSpec
- type LookupStage
- type MatchSpec
- type MatchStage
- type MemAccount
- type MergeSpec
- type MergeWhenMatched
- type MergeWhenNotMatched
- type ObjectExpr
- type OutSpec
- type Pipeline
- type Prefix
- type ProjectField
- type ProjectSpec
- type ProjectStage
- type ReplaceAllExpr
- type ReplaceOneExpr
- type RoundExpr
- type SizeExpr
- type SkipSpec
- type SkipStage
- type SortSpec
- type SortStage
- type SplitExpr
- type Stage
- type StageSpec
- type StrLenExpr
- type SwitchExpr
- type TrimExpr
- type TrimMode
- type UnwindSpec
- type UnwindStage
Constants ¶
const ( DefaultGroupLimit = 50_000 DefaultAccumArrayLimit = 10_000 DefaultMemoryLimit = 256 << 20 )
Variables ¶
var ( // ErrGroupLimitExceeded is returned when $group exceeds the configured // maximum number of unique group keys. ErrGroupLimitExceeded = errors.New("any-store/aggregate: group limit exceeded") // ErrAccumArrayLimitExceeded is returned when a $push or $addToSet // accumulator exceeds the configured maximum array length. ErrAccumArrayLimitExceeded = errors.New("any-store/aggregate: accumulator array limit exceeded") // ErrMemoryLimitExceeded is returned when the blocking stages of a // pipeline retain more than the configured memory budget. ErrMemoryLimitExceeded = errors.New("any-store/aggregate: memory limit exceeded") )
Functions ¶
func Accumulators ¶
func Accumulators() []string
Accumulators returns the $group accumulator vocabulary, sorted and with the leading '$'. The slice is a fresh copy: callers may keep or mutate it.
func CutSink ¶
CutSink splits a trailing sink spec off the pipeline. Returns (nil, p) when the pipeline does not end in one. ParsePipeline guarantees a sink can appear only in the last position.
func ExplainStages ¶
ExplainStages renders the in-pipeline stage list for Explain output, including the top-K annotation a following $skip/$limit folds into $sort.
func HasLookup ¶
HasLookup reports whether the pipeline contains a $lookup spec, including inside $facet sub-pipelines (the root package injects Env.Lookup — and keeps a read tx for it — only then).
func SinkName ¶
SinkName returns the stage name of a sink spec ("$merge"/"$out"), or "" for any other spec.
func SplitPrefix ¶
SplitPrefix consumes the longest pushable pipeline prefix in canonical order — $match* → $sort? → $skip? → $limit? — and returns it together with the remaining stages (which run as in-pipeline operators). Pushdown stops at the first stage that synthesizes documents ($group/$project/$addFields/ $unwind/$count) and at any stage out of canonical order: a $match after $skip/$limit does not commute, and out-of-order combinations are rare enough that running them in-pipeline (correct, just unoptimized) beats rewrite complexity.
$expr predicates are never pushed into the access plan: a leading $match's ordinary filter part enters the prefix (index-eligible) while its expressions come back as a synthesized residual MatchSpec at the head of the remaining stages. A following $sort may still be pushed — filtering a sorted stream preserves its order — but $skip/$limit may not: they would truncate before the residual predicate runs.
func Stages ¶
func Stages() []string
Stages returns the stage vocabulary accepted by the pipeline parser — every stage key ParsePipeline recognizes ($set is $addFields' alias), sorted and with the leading '$'. The slice is a fresh copy: callers may keep or mutate it. Use it to advertise the grammar (docs, error payloads) instead of hand-copying the list.
Types ¶
type AbsExpr ¶
type AbsExpr struct{ Arg Expr }
AbsExpr evaluates $abs; missing/null/non-numeric operand → null.
type Accumulator ¶
type Accumulator interface {
Step(val *anyenc.Value) error
Finalize(out *anyenc.Arena) (*anyenc.Value, error)
}
Accumulator folds the per-row values of one $group output field.
Step receives the already-evaluated argument expression (nil = missing); the value is transient — valid only during the call — so implementations retain data by marshaling into self-owned buffers. Finalize is called once, after the upstream drain; results may be allocated on out or on an accumulator-owned parser (the stage consumes the result before the next emit either way).
type AddFieldsSpec ¶
type AddFieldsSpec struct{ Fields []ProjectField }
func (AddFieldsSpec) String ¶
func (s AddFieldsSpec) String() string
type AddFieldsStage ¶
type AddFieldsStage struct {
Src Stage
Fields []ProjectField
// contains filtered or unexported fields
}
AddFieldsStage overlays computed fields onto each upstream document by mutating it in place (the same pattern FtsIter uses to inject _score): zero-copy, no output object rebuild. Mutation is safe because rows are transient — the underlying parse buffers are rewritten on the next row.
When an upstream $unwind may emit the same underlying document for several consecutive rows (undoOverlay, set by Build), the original value of every overlaid field is captured and rolled back before the next row is pulled: otherwise a later row of the same document would evaluate its expressions against the previous row's overlays instead of the stored fields.
func (*AddFieldsStage) Close ¶
func (s *AddFieldsStage) Close()
func (*AddFieldsStage) String ¶
func (s *AddFieldsStage) String() string
type ArithExpr ¶
ArithExpr evaluates $add/$subtract/$multiply/$divide over numeric operands, plus Mongo's date arithmetic: $add with exactly one dateTime operand shifts it by the numeric sum of millis, and $subtract handles [date, date] → millis and [date, number] → date. Any other mix, a missing/null/non-numeric operand, division by zero, overflow and a non-finite result make the result null (Mongo errors for these; see evalNumber). An empty operand list yields the operator's identity, Mongo semantics ($add 0, $multiply 1).
type ArrayExpr ¶
type ArrayExpr struct {
Exprs []Expr
}
ArrayExpr is an array expression: every element is an expression. Missing elements evaluate to null so the array length is preserved.
type CompareExpr ¶
CompareExpr evaluates $eq/$ne/$gt/$gte/$lt/$lte ($cmp: -1/0/1) over any two values in the engine's canonical cross-type order: bytes.Compare of the marshaled anyenc encoding — the exact order $sort and $min/$max use. The type tag leads the encoding, so types order by tag (null < number < string < false < true < array < object < ... < dateTime; differs from BSON's canonical order, see docs/aggregation.md); within a type the encoding is order-preserving: numbers via the sortable float encoding (-0 normalized to 0), strings bytewise, arrays elementwise, objects by marshaled bytes (field-order-sensitive, consistent with $group key equality). $eq is c == 0, so all seven operators agree by construction. A missing operand marshals as the null tag: missing == null. Operands marshal into two reusable per-expr scratch buffers (expressions are per-pipeline, single-goroutine): alloc-free after warm-up.
func (*CompareExpr) String ¶
func (e *CompareExpr) String() string
type ConcatExpr ¶
type ConcatExpr struct {
Args []Expr
// contains filtered or unexported fields
}
ConcatExpr evaluates $concat over string operands into a reusable scratch buffer (expressions are per-pipeline, single-goroutine), then creates one arena string value. A missing, null, or non-string operand makes the result null (Mongo errors on non-strings; same rationale as evalNumber). An empty operand list yields "", Mongo semantics.
func (*ConcatExpr) String ¶
func (e *ConcatExpr) String() string
type CondExpr ¶
type CondExpr struct {
If, Then, Else Expr
}
CondExpr evaluates $cond in both spellings: [if, then, else] and {"if":..., "then":..., "else":...} (all three required). Only the taken branch is evaluated (lazy, Mongo semantics).
type CountStage ¶
CountStage drains the upstream stream and emits a single {"<field>": N} document.
func (*CountStage) Close ¶
func (s *CountStage) Close()
func (*CountStage) String ¶
func (s *CountStage) String() string
type Ctx ¶
type Ctx struct {
Context context.Context
RowArena *anyenc.Arena
Buf *syncpool.DocBuffer
Mem *MemAccount
}
Ctx carries per-pipeline shared state through the stage chain.
RowArena ownership: the arena is reset only by the current "row owner" — the source stage (once per source row), a blocking stage on its output side (once per emitted row), and $project/$addFields when Build proves nothing below them keeps arena-allocated data alive across pulls. Non-owning stages allocate on RowArena freely and never reset it, so synthesized values and zero-copy aliases of the source document stay valid for the whole life of the row.
type DateAddExpr ¶
type DateAddExpr struct {
Start Expr
Amount Expr
Unit dateUnit
Loc *time.Location
TZ string // original timezone spelling, "" when defaulted to UTC
}
DateAddExpr evaluates $dateAdd. year/quarter/month are calendar-aware in the operative timezone with Mongo's day-of-month clamping (Jan 31 + 1 month = Feb 28; time.AddDate would normalize to Mar 3); week/day add calendar days in the operative timezone, preserving the local clock across DST (Mongo semantics — a repeated wall time resolves to its earlier occurrence); hour/minute/second/millisecond are fixed millis spans. A missing/null/non-dateTime startDate, a non-integral amount and an out-of-range result → null (Mongo errors; see evalNumber).
func (*DateAddExpr) String ¶
func (e *DateAddExpr) String() string
type DateDiffExpr ¶
type DateDiffExpr struct {
Start, End Expr
Unit dateUnit
Loc *time.Location
TZ string
WeekStart time.Weekday
WeekName string // original startOfWeek spelling, "" when defaulted
}
DateDiffExpr evaluates $dateDiff: the signed count of unit boundaries crossed from startDate to endDate (Mongo semantics, not elapsed time — a day diff of 23:59 → 00:01 is 1). year/quarter/month/week/day boundaries are local calendar boundaries in the operative timezone; hour/minute/second/ millisecond are absolute-millis boundaries (timezone-independent). startOfWeek (default sunday) applies to unit "week" only.
func (*DateDiffExpr) String ¶
func (e *DateDiffExpr) String() string
type DatePartExpr ¶
DatePartExpr evaluates $year and $week in the operative timezone. $week is Mongo's Sunday-based 0-53 week of year (days before the year's first Sunday are week 0) — not the ISO week. Both spellings parse: a plain date expression and the {date, timezone?} object form.
func (*DatePartExpr) String ¶
func (e *DatePartExpr) String() string
type DateTruncExpr ¶
type DateTruncExpr struct {
Date Expr
Unit dateUnit
Bin int64 // effective binSize, >= 1
Loc *time.Location
TZ string
WeekStart time.Weekday
WeekName string
// contains filtered or unexported fields
}
DateTruncExpr evaluates $dateTrunc: truncate down to the containing binSize×unit bin. Bins anchor at Mongo's documented reference point — 2000-01-01T00:00:00 (in the operative timezone) for every unit except week, which anchors at the first startOfWeek on or after 2000-01-01 (a Saturday). year/quarter/month/week/day truncate local calendar components (a fall-back-repeated local midnight resolves to its earlier occurrence); hour/minute/second/millisecond subtract the local wall-clock residue on the absolute timeline, so truncation stays monotone and idempotent across DST transitions.
func (*DateTruncExpr) String ¶
func (e *DateTruncExpr) String() string
type Env ¶
type Env struct {
// Lookup resolves $lookup point reads. Required when the pipeline
// contains a LookupSpec; Build rejects the spec without it.
Lookup LookupFunc
}
Env carries execution-environment hooks injected at Build time.
type Expr ¶
type Expr interface {
// Eval returns the expression value for doc; nil means "missing".
// Results may be allocated on a; field refs alias doc (zero-copy),
// except that implicit array traversal collects doc-aliasing elements
// into an a-allocated array container. Either way the result is valid
// only while both doc and a are.
Eval(a *anyenc.Arena, doc *anyenc.Value) (*anyenc.Value, error)
fmt.Stringer
}
Expr is an aggregation expression evaluated against one document.
Supported: field references ("$a.b.c"), literals ({"$literal": x} or any plain value), document/array expressions (objects and arrays whose members are themselves expressions, Mongo semantics), and the compute operators in exprOpParsers — arithmetic/string ($add, $round, $concat, ...), conditional ($cond, $switch, $ifNull), comparison ($eq ... $lte, $cmp) and date ($dateAdd, $dateDiff, $dateTrunc, $year, $week). Remaining compute operators (string transforms, ...) are additive future work: composite Expr implementations dispatched in ParseExpr.
func ParseExpr ¶
ParseExpr parses an aggregation expression value (Mongo expression-context rules): "$path" strings are field references, {"$literal": x} is an escaped literal, single-key $-objects in exprOpParsers are compute operators, non-operator objects are document expressions, arrays are arrays of expressions, everything else is a literal. Unknown $-operators are rejected.
type FacetSpec ¶
FacetSpec is a parsed $facet stage: named sub-pipelines fanned out over one shared input stream. Names and Pipelines are parallel, in spec order.
type FacetStage ¶
FacetStage implements $facet: it consumes its entire input stream, feeding each row to every sub-pipeline incrementally — streaming sub-stages process per-row, blocking sub-stages buffer per their own logic — then emits exactly one document {name: [results], ...}.
The fan-out is synchronous pull inversion: each row is pushed by parking it in the facet's feed and driving the sub-chain until the feed pauses it (errFacetPause). The drive-until-pause protocol guarantees the sub-chain quiesces every round — a pause only surfaces through an upstream pull, and every in-place mutator undoes its overlay strictly before pulling — so non-copying facets always hand the shared row back unmodified. Emitted sub-pipeline documents are marshaled into the facet's result buffer immediately (they are only valid until the sub-chain is driven again); buffered result bytes count against the pipeline's shared memory budget.
A $match at the head of a facet filters the shared stream in-flight; per-facet predicate pushdown (one union scan tagging rows per facet) is a future optimization.
func (*FacetStage) Close ¶
func (s *FacetStage) Close()
func (*FacetStage) String ¶
func (s *FacetStage) String() string
type FieldRefExpr ¶
type FieldRefExpr struct {
Field string // original spelling without "$", for String()
Path []string
}
FieldRefExpr resolves a pre-split document path ("$a.b.c") with Mongo's aggregation field-path semantics, including implicit array traversal; see resolveFieldPath.
func (*FieldRefExpr) String ¶
func (e *FieldRefExpr) String() string
type GroupStage ¶
type GroupStage struct {
Src Stage
Spec GroupSpec
Limits Limits
// contains filtered or unexported fields
}
GroupStage implements $group: a blocking hash aggregation.
Group keys are the marshaled anyenc bytes of the key expression (missing → null, Mongo semantics); the byte encoding is canonical, so byte equality is value equality. Lookups are alloc-free (map[string]X with a string(bytes) conversion the compiler elides); new keys are interned into a grow-only buffer with unsafe.String map keys (the query.In pattern). Group states live in one slab slice in first-seen order, which is also the emit order (unspecified for callers).
func (*GroupStage) Close ¶
func (s *GroupStage) Close()
func (*GroupStage) String ¶
func (s *GroupStage) String() string
type IfNullExpr ¶
type IfNullExpr struct {
Args []Expr
}
IfNullExpr evaluates $ifNull (variadic, Mongo 4.4 form, at least 2 operands): the first operand that is neither null nor missing, else the last operand's value verbatim. Evaluation is lazy left-to-right.
func (*IfNullExpr) String ¶
func (e *IfNullExpr) String() string
type LimitStage ¶
LimitStage emits at most N rows and stops pulling upstream afterwards.
func (*LimitStage) Close ¶
func (s *LimitStage) Close()
func (*LimitStage) String ¶
func (s *LimitStage) String() string
type Limits ¶
type Limits struct {
// MaxGroups caps the number of unique $group keys.
MaxGroups int
// MaxAccumArrayLen caps $push / $addToSet result arrays.
MaxAccumArrayLen int
// MaxMemoryBytes caps retained bytes across all blocking stages.
MaxMemoryBytes int
}
Limits bounds the memory-unbounded parts of a pipeline. Zero values mean "use default"; negative values mean "unlimited".
func (Limits) WithDefaults ¶
type LiteralExpr ¶
type LiteralExpr struct {
// contains filtered or unexported fields
}
LiteralExpr yields the same constant value for every document. The value is detached from the input at parse time (owned bytes + dedicated parser), so it stays valid for the lifetime of the pipeline regardless of caller arenas.
func NewLiteralExpr ¶
func NewLiteralExpr(v *anyenc.Value) (*LiteralExpr, error)
func (*LiteralExpr) String ¶
func (e *LiteralExpr) String() string
type LookupFunc ¶
LookupFunc serves one $lookup point read: key is the anyenc-marshaled primary-key value, buf is stage-owned scratch (DocBuf + Parser) the implementation fetches and parses the stored document with — the returned value stays valid until the same buf is reused. (nil, nil) means no document has that key. Injected by the root package at Build time: the reads must run against the same snapshot the pipeline streams from, and internal/aggregate cannot import the root package to reach it.
type LookupSpec ¶
type LookupSpec struct {
From string // "" = self-join implied
LocalField string
LocalPath []string
As string
}
LookupSpec is a parsed $lookup stage, scoped to a self-join point lookup on the primary key: From (optional) must name the aggregated collection itself — the parser doesn't know that name, so the root package validates it at execution setup — and the foreign field is always the primary key "id" (enforced at parse time).
func (LookupSpec) String ¶
func (s LookupSpec) String() string
type LookupStage ¶
type LookupStage struct {
Src Stage
Spec LookupSpec
Lookup LookupFunc
// contains filtered or unexported fields
}
LookupStage implements the self-join $lookup: for each row it resolves the localField value(s) as primary keys of the aggregated collection and overlays the matched full documents onto the row as the "as" field — always an array (Mongo semantics), empty when nothing matches, replacing any existing field.
A missing or null local value yields an empty array: the primary key is never null, so Mongo's null-matching join cannot apply here. An array local value is set membership: elements are deduplicated by first occurrence and the output keeps first-occurrence order (Mongo leaves the order unspecified). An element of a type no stored key has simply doesn't match.
Fetched documents live in stage-owned per-slot buffers reused every row — zero steady-state allocations once the slot count reaches the row's match count high-water mark.
func (*LookupStage) Close ¶
func (s *LookupStage) Close()
func (*LookupStage) String ¶
func (s *LookupStage) String() string
type MatchSpec ¶
type MatchSpec struct {
Filter query.Filter // nil when the spec is pure $expr (or empty)
Exprs []Expr // nil when the spec has no $expr
}
MatchSpec is a parsed $match stage: the ordinary query-filter part and the $expr predicates, AND-ed together. Filter is index-eligible when the stage sits in the pushdown prefix; Exprs are always residual per-document predicates (Mongo semantics) — they never become index bounds.
type MatchStage ¶
type MatchStage struct {
Src Stage
Filter query.Filter // nil: no ordinary-filter part
Exprs []Expr // nil: no $expr part
// contains filtered or unexported fields
}
MatchStage filters the upstream stream with a query filter and/or $expr predicates (AND-ed, $cond truthiness: false/0/null/missing are false). Matched rows are passed through untouched (1:1); discarded rows are freed by the row owner's per-row arena reset on the following pull. Expression temporaries are allocated on RowArena and die with the row.
func (*MatchStage) Close ¶
func (s *MatchStage) Close()
func (*MatchStage) String ¶
func (s *MatchStage) String() string
type MemAccount ¶
type MemAccount struct {
// contains filtered or unexported fields
}
MemAccount is a coarse retained-bytes budget shared by the blocking stages of one pipeline ($group state, $sort arena). Streaming stages retain nothing and don't report.
func NewMemAccount ¶
func NewMemAccount(limit int) *MemAccount
func (*MemAccount) Add ¶
func (m *MemAccount) Add(n int) error
Add records n retained bytes and fails with ErrMemoryLimitExceeded once the budget is exhausted. n may be negative when a stage shrinks/releases.
func (*MemAccount) Used ¶
func (m *MemAccount) Used() int
Used returns the currently accounted retained bytes.
type MergeSpec ¶
type MergeSpec struct {
Into string
WhenMatched MergeWhenMatched
WhenNotMatched MergeWhenNotMatched
}
MergeSpec is a parsed $merge stage: upsert pipeline results into Into, keyed by the primary key "id" (the only supported "on"; enforced at parse time, mirroring $lookup's pk-only scope).
type MergeWhenMatched ¶
type MergeWhenMatched uint8
MergeWhenMatched selects $merge's action for a result document whose id already exists in the target. The zero value is the default ("merge").
const ( // MergeMatchedMerge overlays the result's top-level fields onto the // existing document (missing fields keep their existing values). MergeMatchedMerge MergeWhenMatched = iota // MergeMatchedReplace replaces the existing document entirely. MergeMatchedReplace // MergeMatchedKeepExisting leaves the existing document untouched. MergeMatchedKeepExisting // MergeMatchedFail aborts the whole write, persisting nothing. MergeMatchedFail )
func (MergeWhenMatched) String ¶
func (m MergeWhenMatched) String() string
type MergeWhenNotMatched ¶
type MergeWhenNotMatched uint8
MergeWhenNotMatched selects $merge's action for a result document whose id does not exist in the target. The zero value is the default ("insert").
const ( // MergeNotMatchedInsert inserts the result document. MergeNotMatchedInsert MergeWhenNotMatched = iota // MergeNotMatchedDiscard drops the result document. MergeNotMatchedDiscard // MergeNotMatchedFail aborts the whole write, persisting nothing. MergeNotMatchedFail )
func (MergeWhenNotMatched) String ¶
func (m MergeWhenNotMatched) String() string
type ObjectExpr ¶
ObjectExpr is a document expression: an object whose values are expressions (Mongo semantics for non-operator objects in expression context, e.g. compound $group keys {"a":"$x","b":"$y"}). Missing member values are omitted from the result, like Mongo.
func (*ObjectExpr) String ¶
func (e *ObjectExpr) String() string
type OutSpec ¶
type OutSpec struct {
Coll string
}
OutSpec is a parsed $out stage: replace the contents of collection Coll with the pipeline results.
type Pipeline ¶
type Pipeline []StageSpec
Pipeline is a parsed aggregation pipeline: an ordered list of stage specs.
func MustParsePipeline ¶
MustParsePipeline is ParsePipeline that panics on error (tests).
func ParsePipeline ¶
ParsePipeline parses a JSON-ish aggregation pipeline (any input accepted by the same parser as Find conditions) into stage specs. The result is fully detached from the input value. Rejections are reported as *query.ParseError with Source "pipeline", whose Path's leading segment is the stage index ("1.$match.a.$gt"); see query.ParseError.
type Prefix ¶
type Prefix struct {
Filter query.Filter // folded leading $match chain; nil if none
Sort query.Sort // nil if no $sort was pushed
Skip int
Limit int // 0 = none
}
Prefix is the leading pipeline part that can be pushed down into the access plan (the regular Find machinery: index/CBO selection, FTS/vector sources, index-order sorts, cursor-level offset skips).
type ProjectField ¶
ProjectField is one output field of $project / $addFields.
type ProjectSpec ¶
type ProjectSpec struct{ Fields []ProjectField }
func (ProjectSpec) String ¶
func (s ProjectSpec) String() string
type ProjectStage ¶
type ProjectStage struct {
Src Stage
Fields []ProjectField
// contains filtered or unexported fields
}
ProjectStage replaces each upstream document with a new object containing only the specified fields. The output is built on RowArena; field values alias subtrees of the input document (zero-copy), which is safe because the input stays valid for the whole row lifetime.
func (*ProjectStage) Close ¶
func (s *ProjectStage) Close()
func (*ProjectStage) String ¶
func (s *ProjectStage) String() string
type ReplaceAllExpr ¶
type ReplaceAllExpr struct {
Input, Find, Replacement Expr
// contains filtered or unexported fields
}
ReplaceAllExpr evaluates $replaceAll: every occurrence of find in input replaced by replacement, left to right, non-overlapping; replaced regions are not rescanned. Same contract as ReplaceOneExpr otherwise: object form, all three required, null/missing or non-string operand → null. An empty find matches at position 0 once, prepending the replacement — same pin as $replaceOne (Mongo docs leave the case unstated; a per-position match would loop).
func (*ReplaceAllExpr) String ¶
func (e *ReplaceAllExpr) String() string
type ReplaceOneExpr ¶
type ReplaceOneExpr struct {
Input, Find, Replacement Expr
// contains filtered or unexported fields
}
ReplaceOneExpr evaluates $replaceOne: the first occurrence of find in input replaced by replacement; no occurrence leaves input unchanged. Object form only, all three parameters required (Mongo). A null or missing operand → null (Mongo); a non-string operand → null too (Mongo errors; same rationale as evalNumber — regex find is likewise out: no regex value type). An empty find matches at position 0, prepending the replacement (Mongo behavior, its docs leave the case unstated). The splice goes through a reusable scratch buffer (per-pipeline, single-goroutine): alloc-free in steady state.
func (*ReplaceOneExpr) String ¶
func (e *ReplaceOneExpr) String() string
type RoundExpr ¶
RoundExpr evaluates $round with half-to-even (banker's) rounding, Mongo semantics: place in [-20, 100], default 0, negative rounds left of the decimal point; an out-of-range or non-integer place → null. Precision is float64: values round by their binary double value ({"$round":[2.345,2]} is 2.35 — the stored double sits above the midpoint), and a place beyond float64 resolution leaves the value unchanged.
type SizeExpr ¶ added in v2.0.1
type SizeExpr struct{ Arg Expr }
SizeExpr evaluates $size: the number of elements in its array operand. A missing, null, or non-array operand → null (Mongo errors; no-error-channel policy, see evalNumber).
type SortSpec ¶
type SortStage ¶
type SortStage struct {
Src Stage
Spec SortSpec
TopK int
// contains filtered or unexported fields
}
SortStage is the blocking in-pipeline $sort over synthesized documents (stored-document sorts are pushed down to the access plan instead).
It mirrors qplanner.SortIter's packed-arena design, but each entry carries the full marshaled document after its sort-key tuple — rows here no longer correspond to stored docIds. With TopK > 0 (a following $skip/$limit was folded in by Build) a max-heap keeps only the smallest K entries: a losing row is built in the arena's spare tail and truncated away — zero retained bytes — and a fragmentation guard re-packs the arena when dead bytes from evictions exceed live data, keeping the high-water mark O(K).
Stability: the full sort uses slices.SortStableFunc over insertion-ordered entries; the top-K path appends a row sequence number to each key, which both totals the order (deterministic heap eviction: of equal keys the earliest rows survive) and makes the final sort stable by construction.
type SplitExpr ¶
type SplitExpr struct {
Input, Delim Expr
}
SplitExpr evaluates $split [string, delimiter]: the array of substrings between delimiter occurrences — adjacent delimiters produce empty strings, no occurrence yields the whole input as a one-element array. The delimiter must be a non-empty string: an empty literal delimiter is a parse error and a delimiter expression evaluating to "" → null (Mongo errors at runtime; no-error-channel policy — likewise a null/missing or non-string operand, where Mongo errors for non-strings; regex delimiters are out: no regex value type). Elements and the result array are arena-allocated per eval: alloc-free in steady state.
type Stage ¶
type Stage interface {
// Next returns the next document, or (nil, nil) at the end of the stream.
// The returned value is valid only until the next Next call on this stage.
Next(ctx *Ctx) (*anyenc.Value, error)
// Close releases stage resources. It must be safe to call multiple times
// and after a mid-stream abort.
Close()
// String describes the stage for Explain output. Never called on the hot
// path.
fmt.Stringer
}
Stage is a pull-driven aggregation operator over anyenc documents.
The chain is strictly synchronous: a stage produces a row only when its consumer asks for one, so row lifetimes are phase-locked across the chain.
func Build ¶
Build compiles parsed stage specs into an executable stage chain on top of source. The source must reset Ctx.RowArena once per row it yields (it is the default row owner). env carries the execution hooks the root package injects (the $lookup point-read function).
Build also performs the arena-ownership analysis: $project / $addFields / $lookup get permission to reset RowArena before pulling (freeing the previous row) when no stage below them keeps arena-allocated data alive across pulls. This keeps the arena footprint O(row) under $unwind row multiplication.
type StageSpec ¶
StageSpec is a parsed pipeline stage description (not yet an executable Stage; see Build).
type StrLenExpr ¶ added in v2.0.1
type StrLenExpr struct {
CP bool // count code points ($strLenCP) instead of bytes ($strLenBytes)
Arg Expr
}
StrLenExpr evaluates $strLenBytes/$strLenCP: the length of the string operand in UTF-8 bytes or code points. A missing, null, or non-string operand → null, and so is a $strLenCP operand that is not valid UTF-8 (Mongo errors for both; no-error-channel policy, see evalNumber). $strLenBytes counts bytes verbatim, valid UTF-8 or not, as Mongo does.
func (*StrLenExpr) String ¶ added in v2.0.1
func (e *StrLenExpr) String() string
type SwitchExpr ¶
SwitchExpr evaluates $switch: cases run lazily in spec order and the first truthy case selects its then branch. No match with no default is a Mongo runtime error; with no per-document error channel the result is null instead (see docs/aggregation.md).
func (*SwitchExpr) String ¶
func (e *SwitchExpr) String() string
type TrimExpr ¶
type TrimExpr struct {
Mode TrimMode
Input Expr
Chars Expr // nil: default whitespace set
// contains filtered or unexported fields
}
TrimExpr evaluates $trim/$ltrim/$rtrim {input, chars?}: strips the leading and/or trailing code points that appear in chars — whole runes, so a multibyte member never shreds mid-character. Absent chars means the default whitespace set (isTrimWhitespace); chars "" is an empty set and trims nothing. A null/missing input, or a non-string input or chars → null (Mongo errors for non-strings; no-error-channel policy). The chars set decodes into a reusable rune scratch: alloc-free in steady state.
type UnwindSpec ¶
type UnwindSpec struct {
Field string // original spelling without "$"
Path []string
PreserveNullAndEmptyArrays bool
}
func (UnwindSpec) String ¶
func (s UnwindSpec) String() string
type UnwindStage ¶
type UnwindStage struct {
Src Stage
Field string
Path []string
PreserveNullAndEmptyArrays bool
// contains filtered or unexported fields
}
UnwindStage emits one row per element of an array field, replacing the array with the current element by mutating the document in place: the element values stay alive because they belong to the original (detached) array value, while the document's field slot is repointed per emission. No arena allocations, no document rebuild.
Before pulling the next source row the original array is restored into the field slot. An upstream stage may hold and re-emit the same document (another $unwind multiplying rows does), so leaving the field pointing at the last element would corrupt every later row of that document.
Mongo semantics: missing / null / empty array drop the document (unless PreserveNullAndEmptyArrays, which emits it as-is — with the field removed for an empty array); a non-array value passes through unchanged.
func (*UnwindStage) Close ¶
func (s *UnwindStage) Close()
func (*UnwindStage) String ¶
func (s *UnwindStage) String() string