@@ -37,20 +37,42 @@ value depends on the order of the documents coming into pipeline. To
3737guarantee a defined order, the :pipeline:`$group` pipeline stage should
3838follow a :pipeline:`$sort` stage.
3939
40- Example
41- -------
40+ .. include:: /includes/note-group-and-window-behavior.rst
4241
43- Consider a ``sales`` collection with the following documents:
42+ Missing Values
43+ ~~~~~~~~~~~~~~
44+ 
45+ The documents in a group may be missing fields or may have fields with
46+ missing values.
47+ 
48+ - If there are no documents from the prior pipeline stage, the 
49+   :pipeline:`$group` stage returns nothing.
50+ - If the field that the :group:`$first` accumulator is processing is
51+   missing, :group:`$first` returns ``null``.
52+   
53+ See the :ref:`missing data <first-missing-values-example>` example.
54+ 
55+ Examples
56+ --------
57+ 
58+ .. _first-accumulator-group-example:
59+ 
60+ Use in ``$group`` Stage
61+ ~~~~~~~~~~~~~~~~~~~~~~~
62+ 
63+ Create the ``sales`` collection:
4464
4565.. code-block:: javascript
4666
47-    { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") }
48-    { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") }
49-    { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") }
50-    { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") }
51-    { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") }
52-    { "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") }
53-    { "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }
67+    db.sales.insertMany( [
68+       { "_id" : 1, "item" : "abc", "price" : 10, "quantity" : 2, "date" : ISODate("2014-01-01T08:00:00Z") },
69+       { "_id" : 2, "item" : "jkl", "price" : 20, "quantity" : 1, "date" : ISODate("2014-02-03T09:00:00Z") },
70+       { "_id" : 3, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-03T09:05:00Z") },
71+       { "_id" : 4, "item" : "abc", "price" : 10, "quantity" : 10, "date" : ISODate("2014-02-15T08:00:00Z") },
72+       { "_id" : 5, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T09:05:00Z") },
73+       { "_id" : 6, "item" : "xyz", "price" : 5, "quantity" : 5, "date" : ISODate("2014-02-15T12:05:10Z") },
74+       { "_id" : 7, "item" : "xyz", "price" : 5, "quantity" : 10, "date" : ISODate("2014-02-15T14:12:12Z") }
75+    ] )
5476
5577Grouping the documents by the ``item`` field, the following operation
5678uses the :group:`$first` accumulator to compute the first sales date for
@@ -65,7 +87,7 @@ each item:
6587          $group:
6688            {
6789              _id: "$item",
68-               firstSalesDate : { $first: "$date" }
90+               firstSale : { $first: "$date" }
6991            }
7092        }
7193      ]
@@ -75,6 +97,64 @@ The operation returns the following results:
7597
7698.. code-block:: javascript
7799
78-    { "_id" : "xyz", "firstSalesDate" : ISODate("2014-02-03T09:05:00Z") }
79-    { "_id" : "jkl", "firstSalesDate" : ISODate("2014-02-03T09:00:00Z") }
80-    { "_id" : "abc", "firstSalesDate" : ISODate("2014-01-01T08:00:00Z") }
100+    [
101+       { _id: 'jkl', firstSale: ISODate("2014-02-03T09:00:00.000Z") },
102+       { _id: 'xyz', firstSale: ISODate("2014-02-03T09:05:00.000Z") },
103+       { _id: 'abc', firstSale: ISODate("2014-01-01T08:00:00.000Z") }
104+    ]
105+ 
106+ .. _first-missing-values-example:
107+ 
108+ Missing Data
109+ ~~~~~~~~~~~~
110+ 
111+ Some documents in the ``badData`` collection are missing fields, other
112+ documents are missing values. 
113+ 
114+ Create the ``badData`` collection:
115+ 
116+ .. code-block:: javascript
117+ 
118+    db.badData.insertMany( [
119+       { "_id": 1, "price": 6, "quantity": 6 },
120+       { "_id": 2, "item": "album", "price": 5 , "quantity": 5  },
121+       { "_id": 7, "item": "tape", "price": 6, "quantity": 6 },
122+       { "_id": 8, "price": 5, "quantity": 5  },
123+       { "_id": 9, "item": "album", "price": 3, "quantity": '' },
124+       { "_id": 10, "item": "tape", "price": 3, "quantity":  4 },
125+       { "_id": 12, "item": "cd", "price": 7  }
126+    ] )
127+ 
128+ Query the ``badData`` collection, grouping the output on the ``item``
129+ field:
130+ 
131+ .. code-block:: javascript
132+ 
133+    db.badData.aggregate( [
134+       { $sort: { item: 1, price: 1 } },
135+       { $group: 
136+          { 
137+             _id: "$item",
138+             inStock: { $first: "$quantity" }
139+          }
140+       }
141+    ] )
142+ 
143+ The :pipeline:`$sort` stage orders the documents and passes them to the
144+ :pipeline:`$group` stage.
145+ 
146+ .. code-block:: javascript
147+ 
148+    [
149+      { _id: null, inStock: 5 },
150+      { _id: 'album', inStock: '' },
151+      { _id: 'cd', inStock: null },
152+      { _id: 'tape', inStock: 4 }
153+    ]
154+ 
155+ :group:`$first` selects the first document from each output group:
156+ 
157+ - The ``_id: null`` group is included.
158+ - When the accumulator field, ``$quantity`` in this example, is 
159+   missing, :group:`$first` returns ``null``.
160+ 
0 commit comments