@@ -6,161 +6,171 @@ $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::
70
-
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``:
9
+ Definition
10
+ ----------
76
11
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:
103
-
104
- .. example::
105
-
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} } } } )
117
-
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:
12
+ .. projection:: $elemMatch
146
13
147
- .. code-block:: javascript
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
+ --------
27
+
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
+ _id: 3,
52
+ zipcode: "63109",
53
+ students: [
54
+ { name: "ajax", school: 100, age: 7 },
55
+ { name: "achilles", school: 100, age: 8 },
56
+ ]
57
+ }
58
+ {
59
+ _id: 4,
60
+ zipcode: "63109",
61
+ students: [
62
+ { name: "barney", school: 102, age: 7 },
63
+ { name: "ruth", school: 102, age: 16 },
64
+ ]
65
+ }
66
+
67
+ Zipcode Search
68
+ ~~~~~~~~~~~~~~
69
+
70
+ The following :method:`~db.collection.find()` operation
71
+ queries for all documents where the value of the ``zipcode``
72
+ field is ``63109``. The :projection:`$elemMatch` projection
73
+ returns only the **first** matching element of the ``students``
74
+ array where the ``school`` field has a value of ``102``:
75
+
76
+ .. code-block:: javascript
77
+
78
+ db.schools.find( { zipcode: "63109" },
79
+ { students: { $elemMatch: { school: 102 } } } )
80
+
81
+ The operation returns the following documents:
82
+
83
+ .. code-block:: javascript
84
+
85
+ { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
86
+ { "_id" : 3 }
87
+ { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
88
+
89
+ - For the document with ``_id`` equal to ``1``, the ``students``
90
+ array contains multiple elements with the ``school`` field
91
+ equal to ``102``. However, the :projection:`$elemMatch`
92
+ projection returns only the first matching element from the
93
+ array.
94
+
95
+ - The document with ``_id`` equal to ``3`` does not contain the
96
+ ``students`` field in the result since no element in its
97
+ ``students`` array matched the :projection:`$elemMatch`
98
+ condition.
99
+
100
+ :projection:`$elemMatch` with Multiple Fields
101
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
102
+
103
+ The :projection:`$elemMatch` projection can specify criteria on multiple
104
+ fields:
105
+
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} } } } )
117
+
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, "students" : [ { "name" : "ruth", "school" : 102, "age" : 16 } ] }
125
+
126
+ Documents with ``_id`` equal to ``3`` and ``_id`` equal to ``4``
127
+ do not contain the ``students`` field since no array element matched
128
+ the :projection:`$elemMatch` criteria.
129
+
130
+ :projection:`$elemMatch` with :method:`~cursor.sort()`
131
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
132
+
133
+ When the :method:`~db.collection.find()` method includes a
134
+ :method:`~cursor.sort()`, the :method:`~db.collection.find()` method
135
+ applies the :method:`~cursor.sort()` to order the matching documents
136
+ **before** it applies the projection. This is a general rule when sorting
137
+ and projecting, and is discussed in :ref:`sort-with-projection`.
138
+
139
+ If an array field contains multiple documents with the same field
140
+ name and the :method:`~db.collection.find()` method includes a
141
+ :method:`~cursor.sort()` on that repeating field, the returned
142
+ documents may not reflect the sort order because the
143
+ :method:`~cursor.sort()` was applied to the elements of the array
144
+ before the :projection:`$elemMatch` projection.
145
+
146
+ An array's sorting value is taken from either its "minimum" or "maximum" value,
147
+ depending on which way the sorting goes. The way that :method:`~cursor.sort()`
148
+ sorts documents containing arrays is described in :ref:`sort-asc-desc`.
149
+
150
+ The following query includes a :method:`~cursor.sort()` to order
151
+ by descending ``students.age`` field:
152
+
153
+ .. code-block:: javascript
154
+
155
+ db.schools.find(
156
+ { zipcode: "63109" },
157
+ { students: { $elemMatch: { school: 102 } } }
158
+ ).sort( { "students.age": -1 } )
148
159
149
- db.schools.find(
150
- { zipcode: 63109 },
151
- { students: { $elemMatch: { school: 102 } } }
152
- ).sort( { "students.age": -1 } )
160
+ The operation applies the :method:`~cursor.sort()` to order the
161
+ documents that have the field ``zipcode`` equal to `` 63109`` and
162
+ then applies the projection. The operation returns the three
163
+ documents in the following order:
153
164
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:
165
+ .. code-block:: javascript
158
166
159
- .. code-block:: javascript
167
+ { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
168
+ { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
169
+ { "_id" : 3 }
160
170
161
- { "_id" : 1, "students" : [ { "name" : "john", "school" : 102, "age" : 10 } ] }
162
- { "_id" : 3 }
163
- { "_id" : 4, "students" : [ { "name" : "barney", "school" : 102, "age" : 7 } ] }
171
+ Even though the sort is descending, the younger student is listed first. This
172
+ is because the sort occured before the older students in Barney's document were
173
+ projected out.
164
174
165
175
.. seealso::
166
176
0 commit comments