@@ -121,5 +121,91 @@ TEST(PositionalProjection, CanMergeWithExistingFieldsInOutputDocument) {
121121 ASSERT_DOCUMENT_EQ (doc, applyPositional (fromjson (" {foo: 3}" ), " foo" , doc, doc));
122122}
123123} // namespace positional_projection_tests
124+
125+ namespace elem_match_projection_tests {
126+ Document applyElemMatch (const BSONObj& match,
127+ const std::string& path,
128+ const Document& input,
129+ const Document& output = {}) {
130+ MutableDocument doc (output);
131+ boost::intrusive_ptr<ExpressionContextForTest> expCtx (new ExpressionContextForTest ());
132+ auto matchObj = BSON (path << BSON (" $elemMatch" << match));
133+ auto matchExpr = uassertStatusOK (MatchExpressionParser::parse (matchObj, expCtx));
134+ projection_executor::applyElemMatchProjection (input, *matchExpr, path, &doc);
135+ return doc.freeze ();
136+ }
137+
138+ TEST (ElemMatchProjection, CorrectlyProjectsNonObjectElement) {
139+ ASSERT_DOCUMENT_EQ (
140+ Document{fromjson (" {foo: [4]}" )},
141+ applyElemMatch (fromjson (" {$in: [4]}" ), " foo" , Document{fromjson (" {foo: [1,2,3,4]}" )}));
142+ ASSERT_DOCUMENT_EQ (
143+ Document{fromjson (" {foo: [4]}" )},
144+ applyElemMatch (fromjson (" {$nin: [1,2,3]}" ), " foo" , Document{fromjson (" {foo: [1,2,3,4]}" )}));
145+ }
146+
147+ TEST (ElemMatchProjection, CorrectlyProjectsObjectElement) {
148+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {foo: [{bar: 6, z: 6}]}" )},
149+ applyElemMatch (fromjson (" {bar: {$gte: 5}}" ),
150+ " foo" ,
151+ Document{fromjson (" {foo: [{bar: 1, z: 1}, {bar: 2, z: 2}, "
152+ " {bar: 6, z: 6}, {bar: 10, z: 10}]}" )}));
153+ }
154+
155+ TEST (ElemMatchProjection, CorrectlyProjectsArrayElement) {
156+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {foo: [[3,4]]}" )},
157+ applyElemMatch (fromjson (" {$gt: [1,2]}" ),
158+ " foo" ,
159+ Document{fromjson (" {foo: [[1,2], [3,4]]}" )}));
160+ }
161+
162+ TEST (ElemMatchProjection, ProjectsAsEmptyDocumentIfInputIsEmpty) {
163+ ASSERT_DOCUMENT_EQ ({}, applyElemMatch (fromjson (" {bar: {$gte: 5}}" ), " foo" , {}));
164+ }
165+
166+ TEST (ElemMatchProjection, RemovesFieldFromOutputDocumentIfUnableToMatchArrayElement) {
167+ ASSERT_DOCUMENT_EQ ({},
168+ applyElemMatch (fromjson (" {bar: {$gte: 5}}" ),
169+ " foo" ,
170+ Document{fromjson (" {foo: [{bar: 1, z: 1}, "
171+ " {bar: 2, z: 2}]}" )}));
172+ auto doc =
173+ Document{fromjson (" {bar: 1, foo: [{bar: 1, z: 1}, {bar: 2, z: 2}, "
174+ " {bar: 6, z: 6}, {bar: 10, z: 10}]}" )};
175+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {bar:1}" )},
176+ applyElemMatch (fromjson (" {bar: {$gte: 20}}" ), " foo" , doc, doc));
177+ }
178+
179+ TEST (ElemMatchProjection, CorrectlyProjectsWithMultipleCriteriaInMatchExpression) {
180+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {foo: [{bar: 2, z: 2}]}" )},
181+ applyElemMatch (fromjson (" {bar: {$gt: 1, $lt: 6}}" ),
182+ " foo" ,
183+ Document{fromjson (" {foo: [{bar: 1, z: 1}, {bar: 2, z: 2}, "
184+ " {bar: 6, z: 6}, {bar: 10, z: 10}]}" )}));
185+ }
186+
187+ TEST (ElemMatchProjection, CanMergeWithExistingFieldsInOutputDocument) {
188+ auto doc =
189+ Document{fromjson (" {foo: [{bar: 1, z: 1}, {bar: 2, z: 2}, "
190+ " {bar: 6, z: 6}, {bar: 10, z: 10}]}" )};
191+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {foo: [{bar: 6, z: 6}]}" )},
192+ applyElemMatch (fromjson (" {bar: {$gte: 5}}" ), " foo" , doc, doc));
193+
194+ doc =
195+ Document{fromjson (" {bar: 1, foo: [{bar: 1, z: 1}, {bar: 2, z: 2}, "
196+ " {bar: 6, z: 6}, {bar: 10, z: 10}]}" )};
197+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {bar:1, foo: [{bar: 6, z: 6}]}" )},
198+ applyElemMatch (fromjson (" {bar: {$gte: 5}}" ), " foo" , doc, doc));
199+ }
200+
201+ TEST (ElemMatchProjection, RemovesFieldFromOutputDocumentIfItContainsNumericSubfield) {
202+ auto doc = Document{BSON (" foo" << BSON (0 << 3 ))};
203+ ASSERT_DOCUMENT_EQ ({}, applyElemMatch (fromjson (" {$gt: 2}" ), " foo" , doc));
204+
205+ doc = Document{BSON (" bar" << 1 << " foo" << BSON (0 << 3 ))};
206+ ASSERT_DOCUMENT_EQ (Document{fromjson (" {bar: 1}" )},
207+ applyElemMatch (fromjson (" {$gt: 2}" ), " foo" , doc, doc));
208+ }
209+ } // namespace elem_match_projection_tests
124210} // namespace projection_executor
125211} // namespace mongo
0 commit comments