Skip to content

Commit ed1ca15

Browse files
committed
CSHARP-683: added support for elemMatch in fields projection.
1 parent 2175557 commit ed1ca15

File tree

4 files changed

+187
-1
lines changed

4 files changed

+187
-1
lines changed

MongoDB.Driver/Builders/FieldsBuilder.cs

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,17 @@ public static IMongoFields Null
4040
}
4141

4242
// public static methods
43+
/// <summary>
44+
/// Returns the first matching element in the array specified by name.
45+
/// </summary>
46+
/// <param name="name">The name.</param>
47+
/// <param name="query">The query.</param>
48+
/// <returns>The build (so method calls can be chained).</returns>
49+
public static FieldsBuilder ElemMatch(string name, IMongoQuery query)
50+
{
51+
return new FieldsBuilder().ElemMatch(name, query);
52+
}
53+
4354
/// <summary>
4455
/// Adds one or more field names to be excluded from the results.
4556
/// </summary>
@@ -103,6 +114,19 @@ public FieldsBuilder()
103114
}
104115

105116
// public methods
117+
/// <summary>
118+
/// Returns the first matching element in the array specified by name.
119+
/// </summary>
120+
/// <param name="name">The name.</param>
121+
/// <param name="query">The query.</param>
122+
/// <returns>The build (so method calls can be chained).</returns>
123+
public FieldsBuilder ElemMatch(string name, IMongoQuery query)
124+
{
125+
var elemMatchDocument = new BsonDocument("$elemMatch", query.ToBsonDocument());
126+
_document.Add(name, elemMatchDocument);
127+
return this;
128+
}
129+
106130
/// <summary>
107131
/// Adds one or more field names to be excluded from the results.
108132
/// </summary>
@@ -194,6 +218,18 @@ public static IMongoFields Null
194218
}
195219

196220
// public static methods
221+
/// <summary>
222+
/// Returns the first matching element in the array specified by name.
223+
/// </summary>
224+
/// <typeparam name="TValue">The type of the value.</typeparam>
225+
/// <param name="memberExpression">The member expression.</param>
226+
/// <param name="elementQueryBuilderFunction">The element query builder function.</param>
227+
/// <returns>The build (so method calls can be chained).</returns>
228+
public static FieldsBuilder<TDocument> ElemMatch<TValue>(Expression<Func<TDocument, IEnumerable<TValue>>> memberExpression, Func<QueryBuilder<TValue>, IMongoQuery> elementQueryBuilderFunction)
229+
{
230+
return new FieldsBuilder<TDocument>().ElemMatch<TValue>(memberExpression, elementQueryBuilderFunction);
231+
}
232+
197233
/// <summary>
198234
/// Adds one or more field names to be excluded from the results.
199235
/// </summary>
@@ -262,6 +298,23 @@ public FieldsBuilder()
262298
}
263299

264300
// public methods
301+
/// <summary>
302+
/// Returns the first matching element in the array specified by name.
303+
/// </summary>
304+
/// <typeparam name="TValue">The type of the value.</typeparam>
305+
/// <param name="memberExpression">The member expression.</param>
306+
/// <param name="elementQueryBuilderFunction">The element query builder function.</param>
307+
/// <returns>The build (so method calls can be chained).</returns>
308+
public FieldsBuilder<TDocument> ElemMatch<TValue>(Expression<Func<TDocument, IEnumerable<TValue>>> memberExpression, Func<QueryBuilder<TValue>, IMongoQuery> elementQueryBuilderFunction)
309+
{
310+
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(memberExpression);
311+
var itemSerializationInfo = _serializationInfoHelper.GetItemSerializationInfo("ElemMatch", serializationInfo);
312+
var elementQueryBuilder = new QueryBuilder<TValue>(_serializationInfoHelper);
313+
var elementQuery = elementQueryBuilderFunction(elementQueryBuilder);
314+
_fieldsBuilder.ElemMatch(serializationInfo.ElementName, elementQuery);
315+
return this;
316+
}
317+
265318
/// <summary>
266319
/// Adds one or more field names to be excluded from the results.
267320
/// </summary>

MongoDB.DriverUnitTests/Builders/FieldsBuilderTests.cs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,22 @@ namespace MongoDB.DriverUnitTests.Builders
2222
[TestFixture]
2323
public class FieldsBuilderTests
2424
{
25+
[Test]
26+
public void TestElemMatch()
27+
{
28+
var fields = Fields.ElemMatch("a2", Query.EQ("b", 10));
29+
string expected = "{ \"a2\" : { \"$elemMatch\" : { \"b\" : 10 } } }";
30+
Assert.AreEqual(expected, fields.ToJson());
31+
}
32+
33+
[Test]
34+
public void TestIncludeElemMatch()
35+
{
36+
var fields = Fields.Include("x").ElemMatch("a2", Query.EQ("b", 10));
37+
string expected = "{ \"x\" : 1, \"a2\" : { \"$elemMatch\" : { \"b\" : 10 } } }";
38+
Assert.AreEqual(expected, fields.ToJson());
39+
}
40+
2541
[Test]
2642
public void TestInclude()
2743
{
@@ -85,4 +101,4 @@ public void TestIncludeSliceNameSkipLimit()
85101
Assert.AreEqual(expected, fields.ToJson());
86102
}
87103
}
88-
}
104+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/* Copyright 2010-2013 10gen Inc.
2+
*
3+
* Licensed under the Apache License, Version 2.0 (the "License");
4+
* you may not use this file except in compliance with the License.
5+
* You may obtain a copy of the License at
6+
*
7+
* http://www.apache.org/licenses/LICENSE-2.0
8+
*
9+
* Unless required by applicable law or agreed to in writing, software
10+
* distributed under the License is distributed on an "AS IS" BASIS,
11+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
* See the License for the specific language governing permissions and
13+
* limitations under the License.
14+
*/
15+
16+
using MongoDB.Bson;
17+
using MongoDB.Driver.Builders;
18+
using NUnit.Framework;
19+
20+
namespace MongoDB.DriverUnitTests.Builders
21+
{
22+
[TestFixture]
23+
public class FieldsBuilderTypedTests
24+
{
25+
public class TestClass
26+
{
27+
public int[] a;
28+
public SubClass[] a2;
29+
public int x;
30+
}
31+
32+
public class SubClass
33+
{
34+
public int b;
35+
}
36+
37+
[Test]
38+
public void TestElemMatch()
39+
{
40+
var fields = Fields<TestClass>.ElemMatch(tc => tc.a2, qb => qb.EQ(tc => tc.b, 10));
41+
string expected = "{ \"a2\" : { \"$elemMatch\" : { \"b\" : 10 } } }";
42+
Assert.AreEqual(expected, fields.ToJson());
43+
}
44+
45+
[Test]
46+
public void TestIncludeElemMatch()
47+
{
48+
var fields = Fields<TestClass>.Include(tc => tc.x).ElemMatch(tc => tc.a2, qb => qb.EQ(tc => tc.b, 10));
49+
string expected = "{ \"x\" : 1, \"a2\" : { \"$elemMatch\" : { \"b\" : 10 } } }";
50+
Assert.AreEqual(expected, fields.ToJson());
51+
}
52+
53+
[Test]
54+
public void TestInclude()
55+
{
56+
var fields = Fields<TestClass>.Include(tc => tc.a);
57+
string expected = "{ \"a\" : 1 }";
58+
Assert.AreEqual(expected, fields.ToJson());
59+
}
60+
61+
[Test]
62+
public void TestExclude()
63+
{
64+
var fields = Fields<TestClass>.Exclude(tc => tc.a);
65+
string expected = "{ \"a\" : 0 }";
66+
Assert.AreEqual(expected, fields.ToJson());
67+
}
68+
69+
[Test]
70+
public void TestSliceNameSize()
71+
{
72+
var fields = Fields<TestClass>.Slice(tc => tc.a, 10);
73+
string expected = "{ \"a\" : { \"$slice\" : 10 } }";
74+
Assert.AreEqual(expected, fields.ToJson());
75+
}
76+
77+
[Test]
78+
public void TestSliceNameSkipLimit()
79+
{
80+
var fields = Fields<TestClass>.Slice(tc => tc.a, 10, 20);
81+
string expected = "{ \"a\" : { \"$slice\" : [10, 20] } }";
82+
Assert.AreEqual(expected, fields.ToJson());
83+
}
84+
[Test]
85+
public void TestIncludeInclude()
86+
{
87+
var fields = Fields<TestClass>.Include(tc => tc.x).Include(tc => tc.a);
88+
string expected = "{ \"x\" : 1, \"a\" : 1 }";
89+
Assert.AreEqual(expected, fields.ToJson());
90+
}
91+
92+
[Test]
93+
public void TesIncludetExclude()
94+
{
95+
var fields = Fields<TestClass>.Include(tc => tc.x).Exclude(tc => tc.a);
96+
string expected = "{ \"x\" : 1, \"a\" : 0 }";
97+
Assert.AreEqual(expected, fields.ToJson());
98+
}
99+
100+
[Test]
101+
public void TestIncludeSliceNameSize()
102+
{
103+
var fields = Fields<TestClass>.Include(tc => tc.x).Slice(tc => tc.a, 10);
104+
string expected = "{ \"x\" : 1, \"a\" : { \"$slice\" : 10 } }";
105+
Assert.AreEqual(expected, fields.ToJson());
106+
}
107+
108+
[Test]
109+
public void TestIncludeSliceNameSkipLimit()
110+
{
111+
var fields = Fields<TestClass>.Include(tc => tc.x).Slice(tc => tc.a, 10, 20);
112+
string expected = "{ \"x\" : 1, \"a\" : { \"$slice\" : [10, 20] } }";
113+
Assert.AreEqual(expected, fields.ToJson());
114+
}
115+
}
116+
}

MongoDB.DriverUnitTests/MongoDB.DriverUnitTests.csproj

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@
9090
<Link>TestEnvironment.cs</Link>
9191
</Compile>
9292
<Compile Include="Builders\CollectionOptionsBuilderTests.cs" />
93+
<Compile Include="Builders\FieldsBuilderTypedTests.cs" />
9394
<Compile Include="Builders\FieldsBuilderTests.cs" />
9495
<Compile Include="Builders\GeoNearOptionsBuilderTests.cs" />
9596
<Compile Include="Builders\GroupByBuilderTests.cs" />

0 commit comments

Comments
 (0)