@@ -6,161 +6,173 @@ $elemMatch (projection)
6
6
7
7
.. default-domain:: mongodb
8
8
9
- .. projection:: $elemMatch
10
-
11
- .. versionadded:: 2.2
12
-
13
- The :projection:`$elemMatch` projection operator limits the contents
14
- of an array field that is included in the query results to contain
15
- only the array element that matches the :projection:`$elemMatch`
16
- condition.
17
-
18
- .. note::
19
-
20
- - The elements of the array are documents.
21
-
22
- - If multiple elements match the :projection:`$elemMatch`
23
- condition, the operator returns the **first** matching element
24
- in the array.
25
-
26
- - The :projection:`$elemMatch` projection operator is similar to
27
- the positional :projection:`$` projection operator.
28
-
29
- The examples on the :projection:`$elemMatch` projection operator
30
- assumes a collection ``school`` with the following documents:
31
-
32
- .. code-block:: javascript
33
-
34
- {
35
- _id: 1,
36
- zipcode: "63109",
37
- students: [
38
- { name: "john", school: 102, age: 10 },
39
- { name: "jess", school: 102, age: 11 },
40
- { name: "jeff", school: 108, age: 15 }
41
- ]
42
- }
43
- {
44
- _id: 2,
45
- zipcode: "63110",
46
- students: [
47
- { name: "ajax", school: 100, age: 7 },
48
- { name: "achilles", school: 100, age: 8 },
49
- ]
50
- }
51
-
52
- {
53
- _id: 3,
54
- zipcode: "63109",
55
- students: [
56
- { name: "ajax", school: 100, age: 7 },
57
- { name: "achilles", school: 100, age: 8 },
58
- ]
59
- }
60
-
61
- {
62
- _id: 4,
63
- zipcode: "63109",
64
- students: [
65
- { name: "barney", school: 102, age: 7 },
66
- ]
67
- }
68
-
69
- .. example::
9
+ Definition
10
+ ----------
70
11
71
- The following :method:`~db.collection.find()` operation
72
- queries for all documents where the value of the ``zipcode``
73
- field is ``63109``. The :projection:`$elemMatch` projection
74
- returns only the **first** matching element of the ``students``
75
- array where the ``school`` field has a value of ``102``:
76
-
77
- .. code-block:: javascript
78
-
79
- db.schools.find( { zipcode: "63109" },
80
- { students: { $elemMatch: { school: 102 } } } )
81
-
82
- The operation returns the following documents:
83
-
84
- .. code-block:: javascript
85
-
86
- { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
87
- { "_id" : 3 }
88
- { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
89
-
90
- - For the document with ``_id`` equal to ``1``, the ``students``
91
- array contains multiple elements with the ``school`` field
92
- equal to ``102``. However, the :projection:`$elemMatch`
93
- projection returns only the first matching element from the
94
- array.
95
-
96
- - The document with ``_id`` equal to ``3`` does not contain the
97
- ``students`` field in the result since no element in its
98
- ``students`` array matched the :projection:`$elemMatch`
99
- condition.
100
-
101
- The :projection:`$elemMatch` projection can specify criteria on multiple
102
- fields:
12
+ .. projection:: $elemMatch
103
13
104
- .. example::
14
+ .. versionadded:: 2.2
15
+
16
+ The :projection:`$elemMatch` operator limits the contents of an
17
+ ``<array>`` field from the query results to contain only the **first**
18
+ element matching the :projection:`$elemMatch` condition.
19
+
20
+ Usage Considerations
21
+ --------------------
22
+
23
+ .. include:: /includes/fact-positional-projection-vs-elemmatch.rst
24
+
25
+ Examples
26
+ --------
105
27
106
- The following :method:`~db.collection.find()` operation
107
- queries for all documents where the value of the ``zipcode``
108
- field is ``63109``. The projection includes the **first**
109
- matching element of the ``students`` array where the ``school``
110
- field has a value of ``102`` **and** the ``age`` field is greater
111
- than ``10``:
112
-
113
- .. code-block:: javascript
114
-
115
- db.schools.find( { zipcode: "63109" },
116
- { students: { $elemMatch: { school: 102, age: { $gt: 10} } } } )
28
+ The examples on the :projection:`$elemMatch` projection operator
29
+ assumes a collection ``school`` with the following documents:
30
+
31
+ .. code-block:: javascript
32
+
33
+ {
34
+ _id: 1,
35
+ zipcode: "63109",
36
+ students: [
37
+ { name: "john", school: 102, age: 10 },
38
+ { name: "jess", school: 102, age: 11 },
39
+ { name: "jeff", school: 108, age: 15 }
40
+ ]
41
+ }
42
+ {
43
+ _id: 2,
44
+ zipcode: "63110",
45
+ students: [
46
+ { name: "ajax", school: 100, age: 7 },
47
+ { name: "achilles", school: 100, age: 8 },
48
+ ]
49
+ }
50
+
51
+ {
52
+ _id: 3,
53
+ zipcode: "63109",
54
+ students: [
55
+ { name: "ajax", school: 100, age: 7 },
56
+ { name: "achilles", school: 100, age: 8 },
57
+ ]
58
+ }
59
+
60
+ {
61
+ _id: 4,
62
+ zipcode: "63109",
63
+ students: [
64
+ { name: "barney", school: 102, age: 7 },
65
+ { name: "ruth", school: 102, age: 16 },
66
+ ]
67
+ }
68
+
69
+ Zipcode Search
70
+ ~~~~~~~~~~~~~~
71
+
72
+ The following :method:`~db.collection.find()` operation
73
+ queries for all documents where the value of the ``zipcode``
74
+ field is ``63109``. The :projection:`$elemMatch` projection
75
+ returns only the **first** matching element of the ``students``
76
+ array where the ``school`` field has a value of ``102``:
77
+
78
+ .. code-block:: javascript
79
+
80
+ db.schools.find( { zipcode: "63109" },
81
+ { students: { $elemMatch: { school: 102 } } } )
82
+
83
+ The operation returns the following documents:
84
+
85
+ .. code-block:: javascript
86
+
87
+ { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
88
+ { "_id" : 3 }
89
+ { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
90
+
91
+ - For the document with ``_id`` equal to ``1``, the ``students``
92
+ array contains multiple elements with the ``school`` field
93
+ equal to ``102``. However, the :projection:`$elemMatch`
94
+ projection returns only the first matching element from the
95
+ array.
96
+
97
+ - The document with ``_id`` equal to ``3`` does not contain the
98
+ ``students`` field in the result since no element in its
99
+ ``students`` array matched the :projection:`$elemMatch`
100
+ condition.
101
+
102
+ :projection:`$elemMatch` with Multiple Fields
103
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
104
+
105
+ The :projection:`$elemMatch` projection can specify criteria on multiple
106
+ fields:
107
+
108
+ The following :method:`~db.collection.find()` operation
109
+ queries for all documents where the value of the ``zipcode``
110
+ field is ``63109``. The projection includes the **first**
111
+ matching element of the ``students`` array where the ``school``
112
+ field has a value of ``102`` **and** the ``age`` field is greater
113
+ than ``10``:
114
+
115
+ .. code-block:: javascript
116
+
117
+ db.schools.find( { zipcode: "63109" },
118
+ { students: { $elemMatch: { school: 102, age: { $gt: 10} } } } )
119
+
120
+ The operation returns the three documents that have ``zipcode`` equal to ``63109``:
121
+
122
+ .. code-block:: javascript
123
+
124
+ { "_id" : 1, "students" : [ { "name" : "jess", "school" : 102, "age" : 11 } ] }
125
+ { "_id" : 3 }
126
+ { "_id" : 4, "students" : [ { "name" : "ruth", "school" : 102, "age" : 16 } ] }
127
+
128
+ Documents with ``_id`` equal to ``3`` and ``_id`` equal to ``4``
129
+ do not contain the ``students`` field since no array element matched
130
+ the :projection:`$elemMatch` criteria.
131
+
132
+ :projection:`$elemMatch` with :method:`~cursor.sort()`
133
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
134
+
135
+ When the :method:`~db.collection.find()` method includes a
136
+ :method:`~cursor.sort()`, the :method:`~db.collection.find()` method
137
+ applies the :method:`~cursor.sort()` to order the matching documents
138
+ **before** it applies the projection. This is a general rule when sorting
139
+ and projecting, and is discussed in :ref:`sort-with-projection`.
140
+
141
+ If an array field contains multiple documents with the same field
142
+ name and the :method:`~db.collection.find()` method includes a
143
+ :method:`~cursor.sort()` on that repeating field, the returned
144
+ documents may not reflect the sort order because the
145
+ :method:`~cursor.sort()` was applied to the elements of the array
146
+ before the :projection:`$elemMatch` projection.
147
+
148
+ An array's sorting value is taken from either its "minimum" or "maximum" value,
149
+ depending on which way the sorting goes. The way that :method:`~cursor.sort()`
150
+ sorts documents containing arrays is described in :ref:`sort-asc-desc`.
151
+
152
+ The following query includes a :method:`~cursor.sort()` to order
153
+ by descending ``students.age`` field:
117
154
118
- The operation returns the three documents that have ``zipcode`` equal to ``63109``:
119
-
120
- .. code-block:: javascript
121
-
122
- { "_id" : 1, "students" : [ { "name" : "jess", "school" : 102, "age" : 11 } ] }
123
- { "_id" : 3 }
124
- { "_id" : 4 }
125
-
126
- Documents with ``_id`` equal to ``3`` and ``_id`` equal to ``4``
127
- do not contain the ``students`` field since no element matched
128
- the :projection:`$elemMatch` criteria.
129
-
130
- When the :method:`~db.collection.find()` method includes a
131
- :method:`~cursor.sort()`, the :method:`~db.collection.find()` method
132
- applies the :method:`~cursor.sort()` to order the matching documents
133
- **before** it applies the projection.
134
-
135
- If an array field contains multiple documents with the same field
136
- name and the :method:`~db.collection.find()` method includes a
137
- :method:`~cursor.sort()` on that repeating field, the returned
138
- documents may not reflect the sort order because the
139
- :method:`~cursor.sort()` was applied to the elements of the array
140
- before the :projection:`$elemMatch` projection.
141
-
142
- .. example::
143
-
144
- The following query includes a :method:`~cursor.sort()` to order
145
- by descending ``students.age`` field:
155
+ .. code-block:: javascript
146
156
147
- .. code-block:: javascript
157
+ db.schools.find(
158
+ { zipcode: "63109" },
159
+ { students: { $elemMatch: { school: 102 } } }
160
+ ).sort( { "students.age": -1 } )
148
161
149
- db.schools.find(
150
- { zipcode: 63109 },
151
- { students: { $elemMatch: { school: 102 } } }
152
- ).sort( { "students.age": -1 } )
162
+ The operation applies the :method:`~cursor.sort()` to order the
163
+ documents that have the field ``zipcode`` equal to `` 63109`` and
164
+ then applies the projection. The operation returns the three
165
+ documents in the following order:
153
166
154
- The operation applies the :method:`~cursor.sort()` to order the
155
- documents that have the field ``zipcode`` equal to ``63109`` and
156
- then applies the projection. The operation returns the three
157
- documents in the following order:
167
+ .. code-block:: javascript
158
168
159
- .. code-block:: javascript
169
+ { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
170
+ { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
171
+ { "_id" : 3 }
160
172
161
- { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
162
- { "_id" : 3 }
163
- { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
173
+ Even though the sort is descending, the younger student is listed first. This
174
+ is because the sort occured before the older students in Barney's document were
175
+ projected out.
164
176
165
177
.. seealso::
166
178
0 commit comments