|
| 1 | +======================= |
| 2 | +$first (array operator) |
| 3 | +======================= |
| 4 | + |
| 5 | +.. default-domain:: mongodb |
| 6 | + |
| 7 | +.. contents:: On this page |
| 8 | + :local: |
| 9 | + :backlinks: none |
| 10 | + :depth: 1 |
| 11 | + :class: singlecol |
| 12 | + |
| 13 | +Definition |
| 14 | +---------- |
| 15 | + |
| 16 | +.. expression:: $first |
| 17 | + |
| 18 | + .. versionadded:: 4.4 |
| 19 | + |
| 20 | + Returns the first element in an array. |
| 21 | + |
| 22 | + .. note:: Disambiguation |
| 23 | + |
| 24 | + |
| 25 | + This page describes the :expression:`$first` array operator. For |
| 26 | + the :group:`$first` aggregation accumulator, see :group:`$first |
| 27 | + (aggregation accumulator) <$first>`. |
| 28 | + |
| 29 | +.. seealso:: |
| 30 | + |
| 31 | + :expression:`$last` |
| 32 | + |
| 33 | +Syntax |
| 34 | +------ |
| 35 | + |
| 36 | +:expression:`$first` has the following syntax: |
| 37 | + |
| 38 | +.. code-block:: javascript |
| 39 | + |
| 40 | + { $first: <expression> } |
| 41 | + |
| 42 | +The ``<expression>`` can be any valid :ref:`expression |
| 43 | +<aggregation-expressions>` as long as it resolves to an array, |
| 44 | +null or missing. For more information on expressions, see |
| 45 | +:ref:`aggregation-expressions`. |
| 46 | + |
| 47 | +The :expression:`$first` operator is an alias for the following |
| 48 | +:expression:`$arrayElemAt` expression: |
| 49 | + |
| 50 | +.. code-block:: javascript |
| 51 | + |
| 52 | + { $arrayElemAt: [ <array expression>, 0 ] } |
| 53 | + |
| 54 | +Behavior |
| 55 | +-------- |
| 56 | + |
| 57 | +Valid Operands |
| 58 | +~~~~~~~~~~~~~~ |
| 59 | + |
| 60 | +Valid operand for :expression:`$first` must resolve to an array, |
| 61 | +null, or missing |
| 62 | + |
| 63 | +- If the operand resolves to a non-empty array, :expression:`$first` |
| 64 | + returns the first element in the array: |
| 65 | + |
| 66 | +- If the operand resolves to an empty array ``[]``, |
| 67 | + :expression:`$first` does not return a value. |
| 68 | + |
| 69 | +- If the operand is null or missing, :expression:`$first` returns null. |
| 70 | + |
| 71 | +For example, create a test collection ``example1`` with the following |
| 72 | +documents: |
| 73 | + |
| 74 | +.. code-block:: javascript |
| 75 | + |
| 76 | + db.example1.insertMany([ |
| 77 | + { "_id" : 1, "x" : [ 1, 2, 3 ] }, // Non-empty array |
| 78 | + { "_id" : 2, "x" : [ [ ] ] }, // Non-empty array |
| 79 | + { "_id" : 3, "x" : [ null ] }, // Non-empty array |
| 80 | + { "_id" : 4, "x" : [ ] }, // Empty array |
| 81 | + { "_id" : 5, "x" : null }, // Is null |
| 82 | + { "_id" : 6 } // Is Missing |
| 83 | + ]) |
| 84 | + |
| 85 | +Then, the following adds a new field ``firstElem`` whose value is |
| 86 | +derived from applying the :expression:`$first` operator to the ``x`` |
| 87 | +field: |
| 88 | + |
| 89 | +.. code-block:: javascript |
| 90 | + |
| 91 | + db.example1.aggregate([ |
| 92 | + { $addFields: { firstElem: { $first: "$x" } } } |
| 93 | + ]) |
| 94 | + |
| 95 | +The operator returns the following documents: |
| 96 | + |
| 97 | +.. code-block:: javascript |
| 98 | + :copyable: false |
| 99 | + |
| 100 | + { "_id" : 1, "x" : [ 1, 2, 3 ], "firstElem" : 1 } |
| 101 | + { "_id" : 2, "x" : [ [ ] ], "firstElem" : [ ] } |
| 102 | + { "_id" : 3, "x" : [ null ], "firstElem" : null } |
| 103 | + { "_id" : 4, "x" : [ ] } // No output |
| 104 | + { "_id" : 5, "x" : null, "firstElem" : null } |
| 105 | + { "_id" : 6, "firstElem" : null } |
| 106 | + |
| 107 | +Invalid Operands |
| 108 | +~~~~~~~~~~~~~~~~ |
| 109 | + |
| 110 | +If the operand does not resolve to an array, null, or missing, the |
| 111 | +aggregation operation as a whole errors. |
| 112 | + |
| 113 | +For example, create a test collection ``example2`` with the following |
| 114 | +documents: |
| 115 | + |
| 116 | +.. code-block:: javascript |
| 117 | + |
| 118 | + db.example2.insertMany([ |
| 119 | + { "_id" : 1, "x" : [ 1, 2, 3 ] }, |
| 120 | + { "_id" : 2, "x" : 2 }, // x is not an array/null or missing |
| 121 | + ]) |
| 122 | + |
| 123 | +Then, the following aggregation operation returns an error because of |
| 124 | +the ``{ "_id" : 2, "x" : 2 }`` document: |
| 125 | + |
| 126 | +.. code-block:: javascript |
| 127 | + |
| 128 | + db.example2.aggregate( { $addFields: { firstElem: { $first: "$x" } } } ) |
| 129 | + |
| 130 | +That is, the operation returns the following: |
| 131 | + |
| 132 | +.. code-block:: javascript |
| 133 | + :copyable: false |
| 134 | + |
| 135 | + 2020-01-20T18:31:13.431-05:00 E QUERY [js] uncaught exception: Error: command failed: { |
| 136 | + "ok" : 0, |
| 137 | + "errmsg" : "$first's argument must be an array, but is double", |
| 138 | + "code" : 28689, |
| 139 | + "codeName" : "Location28689" |
| 140 | + } : aggregate failed : |
| 141 | + |
| 142 | +Example |
| 143 | +------- |
| 144 | + |
| 145 | +Create a sample collection ``runninglog`` with the following documents: |
| 146 | + |
| 147 | +.. code-block:: javascript |
| 148 | + |
| 149 | + db.runninglog.insertMany([ |
| 150 | + { "_id" : 1, "team" : "Anteater", log: [ { run: 1, distance: 8 }, { run2: 2, distance: 7.5 }, { run: 3, distance: 9.2 } ] }, |
| 151 | + { "_id" : 2, "team" : "Bears", log: [ { run: 1, distance: 18 }, { run2: 2, distance: 17 }, { run: 3, distance: 16 } ] }, |
| 152 | + { "_id" : 3, "team" : "Cobras", log: [ { run: 1, distance: 2 } ] } |
| 153 | + ]) |
| 154 | + |
| 155 | +The following aggregation uses the :expression:`$first` and |
| 156 | +:expression:`$last` operator on the ``log`` array to retrieve the |
| 157 | +information for the first run and the last run: |
| 158 | + |
| 159 | +.. code-block:: javascript |
| 160 | + |
| 161 | + db.runninglog.aggregate([ |
| 162 | + { $addFields: { firstrun: { $first: "$log" }, lastrun: { $last: "$log" } } } |
| 163 | + ]) |
| 164 | + |
| 165 | +The operation returns the following results: |
| 166 | + |
| 167 | +.. code-block:: javascript |
| 168 | + |
| 169 | + { "_id" : 1, "team" : "Anteater", "log" : [ { "run" : 1, "distance" : 8 }, { "run2" : 2, "distance" : 7.5 }, { "run" : 3, "distance" : 9.2 } ], |
| 170 | + "firstrun" : { "run" : 1, "distance" : 8 }, "lastrun" : { "run" : 3, "distance" : 9.2 } } |
| 171 | + { "_id" : 2, "team" : "Bears", "log" : [ { "run" : 1, "distance" : 18 }, { "run2" : 2, "distance" : 17 }, { "run" : 3, "distance" : 16 } ], |
| 172 | + "firstrun" : { "run" : 1, "distance" : 18 }, "lastrun" : { "run" : 3, "distance" : 16 } } |
| 173 | + { "_id" : 3, "team" : "Cobras", "log" : [ { "run" : 1, "distance" : 2 } ], |
| 174 | + "firstrun" : { "run" : 1, "distance" : 2 }, "lastrun" : { "run" : 1, "distance" : 2 } } |
| 175 | + |
| 176 | +To calculate the change between the first and the last distances, the |
| 177 | +following operation uses :expression:`$cond` and :expression:`$size` |
| 178 | +operators to calculate the difference (i.e. :expression:`$subtract`) |
| 179 | +the two distances if there are two or more elements in the ``log`` |
| 180 | +array: |
| 181 | + |
| 182 | +.. code-block:: javascript |
| 183 | + |
| 184 | + db.runninglog.aggregate([ |
| 185 | + { $addFields: { firstrun: { $first: "$log" }, lastrun: { $last: "$log" } } }, |
| 186 | + { $project: { team: 1, progress: |
| 187 | + { |
| 188 | + $cond: { |
| 189 | + if: { $gt: [ { $size:"$log" }, 1 ] } , |
| 190 | + then: { $subtract: [ "$lastrun.distance", "$firstrun.distance"] }, |
| 191 | + else: "Not enough data." } |
| 192 | + } |
| 193 | + |
| 194 | + }} |
| 195 | + ]) |
| 196 | + |
| 197 | +The operation returns the following documents: |
| 198 | + |
| 199 | +.. code-block:: javascript |
| 200 | + :copyable: false |
| 201 | + |
| 202 | + { "_id" : 1, "team" : "Anteater", "progress" : 1.1999999999999993 } |
| 203 | + { "_id" : 2, "team" : "Bears", "progress" : -2 } |
| 204 | + { "_id" : 3, "team" : "Cobras", "progress" : "Not enough data." } |
| 205 | + |
| 206 | +By default, :binary:`~bin.mongosh` uses the 64-bit floating-point |
| 207 | +double for numbers. To improve precision, you can use :ref:`shell-type-decimal` |
| 208 | +instead. |
| 209 | + |
| 210 | +Learn More |
| 211 | +---------- |
| 212 | + |
| 213 | +- :expression:`$last` |
| 214 | + |
| 215 | +- :expression:`$arrayElemAt` |
| 216 | + |
| 217 | +- :expression:`$slice` |
| 218 | + |
| 219 | +- :ref:`agg-quick-ref-operator-array` |
0 commit comments