@@ -48,20 +48,42 @@ value depends on the order of the documents coming into pipeline. To
4848guarantee a defined order, the :pipeline:`$group` pipeline stage should
4949follow a :pipeline:`$sort` stage.
5050
51- Example
52- -------
51+ .. include:: /includes/note-group-and-window-behavior.rst
5352
54- Consider a ``sales`` collection with the following documents:
53+ Missing Values
54+ ~~~~~~~~~~~~~~
55+
56+ The documents in a group may be missing fields or may have fields with
57+ missing values.
58+
59+ - If there are no documents from the prior pipeline stage, the
60+ :pipeline:`$group` stage returns nothing.
61+ - If the field that the :group:`$first` accumulator is processing is
62+ missing, :group:`$first` returns ``null``.
63+
64+ See the :ref:`missing data <first-missing-values-example>` example.
65+
66+ Examples
67+ --------
68+
69+ .. _first-accumulator-group-example:
70+
71+ Use in ``$group`` Stage
72+ ~~~~~~~~~~~~~~~~~~~~~~~
73+
74+ Create the ``sales`` collection:
5575
5676.. code-block:: javascript
5777
58- { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
59- { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
60- { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
61- { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
62- { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }
63- { "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") }
64- { "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }
78+ db.sales.insertMany( [
79+ { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") },
80+ { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") },
81+ { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") },
82+ { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") },
83+ { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") },
84+ { "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") },
85+ { "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }
86+ ] )
6587
6688Grouping the documents by the ``item`` field, the following operation
6789uses the :group:`$first` accumulator to compute the first sales date for
@@ -76,7 +98,7 @@ each item:
7698 $group:
7799 {
78100 _id: "$item",
79- firstSalesDate : { $first: "$date" }
101+ firstSale : { $first: "$date" }
80102 }
81103 }
82104 ]
@@ -86,6 +108,64 @@ The operation returns the following results:
86108
87109.. code-block:: javascript
88110
89- { "_id" : "xyz", "firstSalesDate" : ISODate("2014-02-03T09:05:00Z") }
90- { "_id" : "jkl", "firstSalesDate" : ISODate("2014-02-03T09:00:00Z") }
91- { "_id" : "abc", "firstSalesDate" : ISODate("2014-01-01T08:00:00Z") }
111+ [
112+ { _id: 'jkl', firstSale: ISODate("2014-02-03T09:00:00.000Z") },
113+ { _id: 'xyz', firstSale: ISODate("2014-02-03T09:05:00.000Z") },
114+ { _id: 'abc', firstSale: ISODate("2014-01-01T08:00:00.000Z") }
115+ ]
116+
117+ .. _first-missing-values-example:
118+
119+ Missing Data
120+ ~~~~~~~~~~~~
121+
122+ Some documents in the ``badData`` collection are missing fields, other
123+ documents are missing values.
124+
125+ Create the ``badData`` collection:
126+
127+ .. code-block:: javascript
128+
129+ db.badData.insertMany( [
130+ { "_id": 1, "price": 6, "quantity": 6 },
131+ { "_id": 2, "item": "album", "price": 5 , "quantity": 5 },
132+ { "_id": 7, "item": "tape", "price": 6, "quantity": 6 },
133+ { "_id": 8, "price": 5, "quantity": 5 },
134+ { "_id": 9, "item": "album", "price": 3, "quantity": '' },
135+ { "_id": 10, "item": "tape", "price": 3, "quantity": 4 },
136+ { "_id": 12, "item": "cd", "price": 7 }
137+ ] )
138+
139+ Query the ``badData`` collection, grouping the output on the ``item``
140+ field:
141+
142+ .. code-block:: javascript
143+
144+ db.badData.aggregate( [
145+ { $sort: { item: 1, price: 1 } },
146+ { $group:
147+ {
148+ _id: "$item",
149+ inStock: { $first: "$quantity" }
150+ }
151+ }
152+ ] )
153+
154+ The :pipeline:`$sort` stage orders the documents and passes them to the
155+ :pipeline:`$group` stage.
156+
157+ .. code-block:: javascript
158+
159+ [
160+ { _id: null, inStock: 5 },
161+ { _id: 'album', inStock: '' },
162+ { _id: 'cd', inStock: null },
163+ { _id: 'tape', inStock: 4 }
164+ ]
165+
166+ :group:`$first` selects the first document from each output group:
167+
168+ - The ``_id: null`` group is included.
169+ - When the accumulator field, ``$quantity`` in this example, is
170+ missing, :group:`$first` returns ``null``.
171+
0 commit comments