44
55part of '../cloud_firestore.dart' ;
66
7- /// A pipeline for querying and transforming Firestore data
7+ /// A pipeline for querying and transforming Firestore data.
8+ ///
9+ /// A [Pipeline] is composed of a sequence of stages. Each stage processes the
10+ /// output from the previous one, and the final stage's output is the result of
11+ /// the pipeline's execution.
12+ ///
13+ /// Start with [FirebaseFirestore.pipeline] and a source stage (e.g.
14+ /// [PipelineSource.collection] ), then add transformation and filtering stages.
15+ /// Call [execute] to run the pipeline.
16+ ///
17+ /// Example:
18+ /// ```dart
19+ /// final snapshot = await FirebaseFirestore.instance
20+ /// .pipeline()
21+ /// .collection('users')
22+ /// .where(Expression.field('active').equal(true))
23+ /// .limit(10)
24+ /// .execute();
25+ /// for (final result in snapshot.result) {
26+ /// print(result.data());
27+ /// }
28+ /// ```
29+ ///
30+ /// **Note on execution:** The stages are conceptual. The Firestore backend may
31+ /// optimize execution (e.g., reordering or merging stages) as long as the final
32+ /// result remains the same.
33+ ///
34+ /// **Important limitations:** Pipelines operate on a request/response basis only.
35+ /// They do not utilize or update the local SDK cache, and they do not support
36+ /// realtime snapshot listeners.
837class Pipeline {
938 final FirebaseFirestore _firestore;
1039 final PipelinePlatform _delegate;
@@ -23,7 +52,17 @@ class Pipeline {
2352 return _delegate.stages;
2453 }
2554
26- /// Executes the pipeline and returns a snapshot of the results
55+ /// Executes this pipeline and returns the results as a [PipelineSnapshot] .
56+ ///
57+ /// Example:
58+ /// ```dart
59+ /// final snapshot = await firestore
60+ /// .pipeline()
61+ /// .collection('products')
62+ /// .limit(5)
63+ /// .execute();
64+ /// print('Got ${snapshot.result.length} documents');
65+ /// ```
2766 Future <PipelineSnapshot > execute ({ExecuteOptions ? options}) async {
2867 final optionsMap = options != null
2968 ? {
@@ -54,7 +93,22 @@ class Pipeline {
5493
5594 // Pipeline Actions
5695
57- /// Adds fields to documents using expressions
96+ /// Adds new fields to outputs from previous stages.
97+ ///
98+ /// This stage allows you to compute values on-the-fly based on existing data
99+ /// from previous stages or constants. You can create new fields or overwrite
100+ /// existing ones. The added fields are defined using [Selectable] s, which can
101+ /// be a [Field] (from [Expression.field] ) or an expression with an alias via
102+ /// [Expression.as] .
103+ ///
104+ /// Example:
105+ /// ```dart
106+ /// firestore.pipeline().collection('books').addFields(
107+ /// Expression.field('rating').as('bookRating'),
108+ /// Expression.field('title').stringReplaceAllLiteral('Item', 'Doc').as('title_replaced'),
109+ /// Expression.field('score').abs().as('abs_score'),
110+ /// );
111+ /// ```
58112 Pipeline addFields (
59113 Selectable selectable1, [
60114 Selectable ? selectable2,
@@ -124,7 +178,22 @@ class Pipeline {
124178 );
125179 }
126180
127- /// Aggregates data using aggregate functions
181+ /// Performs aggregation operations on the documents from previous stages.
182+ ///
183+ /// This stage allows you to calculate aggregate values over a set of documents.
184+ /// Define aggregations using [AliasedAggregateFunction] s, typically by calling
185+ /// [PipelineAggregateFunction.as] on [PipelineAggregateFunction] instances
186+ /// such as [Expression.field] with [Expression.sum] , [Expression.average] ,
187+ /// or [CountAll] .
188+ ///
189+ /// Example:
190+ /// ```dart
191+ /// firestore.pipeline().collection('books').aggregate(
192+ /// Expression.field('score').sum().as('total_score'),
193+ /// Expression.field('score').average().as('avg_score'),
194+ /// CountAll().as('count'),
195+ /// );
196+ /// ```
128197 Pipeline aggregate (
129198 AliasedAggregateFunction aggregateFunction1, [
130199 AliasedAggregateFunction ? aggregateFunction2,
@@ -247,7 +316,18 @@ class Pipeline {
247316 );
248317 }
249318
250- /// Gets distinct values based on expressions
319+ /// Returns a set of distinct values from the inputs to this stage.
320+ ///
321+ /// This stage runs through the results from previous stages to include only
322+ /// results with unique combinations of the given [Selectable] expressions
323+ /// (e.g. [Expression.field] , or expressions with [Expression.as] ).
324+ ///
325+ /// Example:
326+ /// ```dart
327+ /// firestore.pipeline().collection('books').distinct(
328+ /// Expression.field('category').as('category'),
329+ /// );
330+ /// ```
251331 Pipeline distinct (
252332 Selectable expression1, [
253333 Selectable ? expression2,
@@ -318,7 +398,23 @@ class Pipeline {
318398 );
319399 }
320400
321- /// Finds nearest vectors using vector similarity search
401+ /// Performs a vector similarity search.
402+ ///
403+ /// Orders the result set by most similar to least similar and returns
404+ /// documents in that order. Requires a vector index on [vectorField] .
405+ /// [vectorValue] is the query embedding; [distanceMeasure] specifies how to
406+ /// compare vectors (e.g. [DistanceMeasure.cosine] ). Use [limit] to return
407+ /// only the first N documents.
408+ ///
409+ /// Example:
410+ /// ```dart
411+ /// firestore.pipeline().collection('books').findNearest(
412+ /// Field('embedding'),
413+ /// [0.1, 0.2, 0.3],
414+ /// DistanceMeasure.cosine,
415+ /// limit: 10,
416+ /// );
417+ /// ```
322418 Pipeline findNearest (
323419 Field vectorField,
324420 List <double > vectorValue,
@@ -337,7 +433,18 @@ class Pipeline {
337433 );
338434 }
339435
340- /// Limits the number of results
436+ /// Limits the maximum number of documents returned by previous stages to
437+ /// [limit] .
438+ ///
439+ /// Useful for pagination (with [offset] ) or to cap data retrieval and
440+ /// improve performance.
441+ ///
442+ /// Example:
443+ /// ```dart
444+ /// firestore.pipeline().collection('books')
445+ /// .sort(Expression.field('rating').descending())
446+ /// .limit(10);
447+ /// ```
341448 Pipeline limit (int limit) {
342449 final stage = _LimitStage (limit);
343450 return Pipeline ._(
@@ -346,7 +453,18 @@ class Pipeline {
346453 );
347454 }
348455
349- /// Offsets the results
456+ /// Skips the first [offset] documents from the results of previous stages.
457+ ///
458+ /// Useful for implementing pagination; typically used with [limit] to control
459+ /// the size of each page.
460+ ///
461+ /// Example:
462+ /// ```dart
463+ /// firestore.pipeline().collection('books')
464+ /// .sort(Expression.field('published').descending())
465+ /// .offset(20)
466+ /// .limit(20);
467+ /// ```
350468 Pipeline offset (int offset) {
351469 final stage = _OffsetStage (offset);
352470 return Pipeline ._(
@@ -355,7 +473,13 @@ class Pipeline {
355473 );
356474 }
357475
358- /// Removes specified fields from documents
476+ /// Removes fields from outputs of previous stages.
477+ ///
478+ /// Example:
479+ /// ```dart
480+ /// firestore.pipeline().collection('books')
481+ /// .removeFields('rating', 'cost');
482+ /// ```
359483 Pipeline removeFields (
360484 String fieldPath1, [
361485 String ? fieldPath2,
@@ -426,7 +550,18 @@ class Pipeline {
426550 );
427551 }
428552
429- /// Replaces documents with the result of an expression
553+ /// Fully overwrites each document with the value of the given expression.
554+ ///
555+ /// This stage allows you to emit a nested map or array as the document: each
556+ /// document from the previous stage is replaced by the evaluated [expression]
557+ /// (e.g. [Expression.field] referencing a nested map or array).
558+ ///
559+ /// Example:
560+ /// ```dart
561+ /// // Emit the 'parents' map as the document.
562+ /// firestore.pipeline().collection('people')
563+ /// .replaceWith(Expression.field('parents'));
564+ /// ```
430565 Pipeline replaceWith (Expression expression) {
431566 final stage = _ReplaceWithStage (expression);
432567 return Pipeline ._(
@@ -435,7 +570,18 @@ class Pipeline {
435570 );
436571 }
437572
438- /// Samples documents using a sampling strategy
573+ /// Performs a pseudo-random sampling of the input documents.
574+ ///
575+ /// Use [PipelineSample.withSize] for a fixed number of documents, or
576+ /// [PipelineSample.withPercentage] for a fraction of the result set.
577+ ///
578+ /// Example:
579+ /// ```dart
580+ /// firestore.pipeline().collection('books')
581+ /// .sample(PipelineSample.withSize(10));
582+ /// firestore.pipeline().collection('books')
583+ /// .sample(PipelineSample.withPercentage(0.5));
584+ /// ```
439585 Pipeline sample (PipelineSample sample) {
440586 final stage = _SampleStage (sample);
441587 return Pipeline ._(
@@ -444,7 +590,19 @@ class Pipeline {
444590 );
445591 }
446592
447- /// Selects specific fields using selectable expressions
593+ /// Selects or creates a set of fields from the outputs of previous stages.
594+ ///
595+ /// Only the selected fields (with their aliases) appear in the output. Use
596+ /// [Expression.field] with [Expression.as] for expressions. Use [addFields]
597+ /// if you only want to add or overwrite fields while keeping the rest.
598+ ///
599+ /// Example:
600+ /// ```dart
601+ /// firestore.pipeline().collection('books').select(
602+ /// Expression.field('name').as('name'),
603+ /// Expression.field('address').toUpperCase().as('upperAddress'),
604+ /// );
605+ /// ```
448606 Pipeline select (
449607 Selectable expression1, [
450608 Selectable ? expression2,
@@ -515,8 +673,20 @@ class Pipeline {
515673 );
516674 }
517675
518- /// Sorts results using one or more ordering specifications.
519- /// Orderings are applied in sequence (e.g. primary sort by first, then by second, etc.).
676+ /// Sorts the documents from previous stages based on one or more orderings.
677+ ///
678+ /// Orderings are applied in sequence (primary sort by the first, then by the
679+ /// second, etc.). If documents have the same value for a field used for
680+ /// sorting, the next ordering is used. Use [Expression.field] with
681+ /// [Expression.descending] and [Expression.ascending] .
682+ ///
683+ /// Example:
684+ /// ```dart
685+ /// firestore.pipeline().collection('books').sort(
686+ /// Expression.field('rating').descending(),
687+ /// Expression.field('title').ascending(),
688+ /// );
689+ /// ```
520690 Pipeline sort (
521691 Ordering order, [
522692 Ordering ? order2,
@@ -587,7 +757,21 @@ class Pipeline {
587757 );
588758 }
589759
590- /// Unnests arrays into separate documents
760+ /// Takes a specified array from the input documents and outputs a document
761+ /// for each element, with the element stored in a field named by the alias.
762+ ///
763+ /// For each document from the previous stage, this stage emits zero or more
764+ /// documents (one per array element). Use [Expression.field] .as() to specify
765+ /// the array and the output field name. Optionally use [indexField] to add
766+ /// the array index to each emitted document.
767+ ///
768+ /// Example:
769+ /// ```dart
770+ /// // Input: { "title": "Guide", "tags": ["comedy", "space"] }
771+ /// // Output: one doc per tag with field "tag".
772+ /// firestore.pipeline().collection('books')
773+ /// .unnest(Expression.field('tags').as('tag'));
774+ /// ```
591775 Pipeline unnest (Selectable expression, [String ? indexField]) {
592776 final stage = _UnnestStage (expression, indexField);
593777 return Pipeline ._(
@@ -596,7 +780,18 @@ class Pipeline {
596780 );
597781 }
598782
599- /// Unions results with another pipeline
783+ /// Performs a union of all documents from this pipeline and [pipeline] ,
784+ /// including duplicates.
785+ ///
786+ /// Documents from the previous stage and from [pipeline] are combined. The
787+ /// order of documents emitted from this stage is undefined.
788+ ///
789+ /// Example:
790+ /// ```dart
791+ /// firestore.pipeline().collection('books').union(
792+ /// firestore.pipeline().collection('magazines'),
793+ /// );
794+ /// ```
600795 Pipeline union (Pipeline pipeline) {
601796 final stage = _UnionStage (pipeline);
602797 return Pipeline ._(
@@ -605,7 +800,23 @@ class Pipeline {
605800 );
606801 }
607802
608- /// Filters documents using a boolean expression
803+ /// Filters the documents from previous stages to only include those matching
804+ /// the specified [BooleanExpression] .
805+ ///
806+ /// This stage applies conditions to the data, similar to a WHERE clause. You
807+ /// can use [Expression.field] with [Expression.equal] , [Expression.greaterThan] ,
808+ /// [Expression.lessThan] , etc., and combine conditions with [Expression.and]
809+ /// and [Expression.or] .
810+ ///
811+ /// Example:
812+ /// ```dart
813+ /// firestore.pipeline().collection('books').where(
814+ /// Expression.and(
815+ /// Expression.field('rating').greaterThan(4.0),
816+ /// Expression.field('genre').equal('Science Fiction'),
817+ /// ),
818+ /// );
819+ /// ```
609820 Pipeline where (BooleanExpression expression) {
610821 final stage = _WhereStage (expression);
611822 return Pipeline ._(
0 commit comments