Skip to content

Commit d6cf4f5

Browse files
author
rstam
committed
Using a different query that always evaluates to false: { _id : { $type : -1 } }. This query is nice because it doesn't depend on the type of _id, because it works equally well at the top level or in an $elemMatch (whether the elements have an _id field or not), and as a bonus it uses the _id index when evaluated at the top level.
1 parent f85fc87 commit d6cf4f5

File tree

3 files changed

+31
-15
lines changed

3 files changed

+31
-15
lines changed

Driver/Linq/Translators/PredicateTranslator.cs

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -207,10 +207,28 @@ private IMongoQuery BuildArrayLengthQuery(Expression variableExpression, Express
207207
return null;
208208
}
209209

210+
private IMongoQuery BuildBooleanQuery(bool value)
211+
{
212+
if (value)
213+
{
214+
return new QueryDocument(); // empty query matches all documents
215+
}
216+
else
217+
{
218+
return _queryBuilder.Type("_id", (BsonType)(-1)); // matches no documents (and uses _id index when used at top level)
219+
}
220+
}
221+
210222
private IMongoQuery BuildBooleanQuery(Expression expression)
211223
{
212224
if (expression.Type == typeof(bool))
213225
{
226+
var constantExpression = expression as ConstantExpression;
227+
if (constantExpression != null)
228+
{
229+
return BuildBooleanQuery((bool)constantExpression.Value);
230+
}
231+
214232
var serializationInfo = _serializationInfoHelper.GetSerializationInfo(expression);
215233
return new QueryDocument(serializationInfo.ElementName, true);
216234
}
@@ -336,9 +354,7 @@ private IMongoQuery BuildConstantQuery(ConstantExpression constantExpression)
336354
var value = constantExpression.Value;
337355
if (value != null && value.GetType() == typeof(bool))
338356
{
339-
// simulate true or false with a tautology or a reverse tautology
340-
// the particular reverse tautology chosen has the nice property that it uses the index to return no results quickly
341-
return new QueryDocument("_id", new BsonDocument("$exists", (bool)value));
357+
return BuildBooleanQuery((bool)value);
342358
}
343359

344360
return null;
@@ -858,7 +874,7 @@ private IMongoQuery BuildStringIndexOfQuery(Expression variableExpression, Expre
858874
if (index >= startIndex + count)
859875
{
860876
// index is outside of the substring so no match is possible
861-
return _queryBuilder.NotExists("_id"); // matches no documents
877+
return BuildBooleanQuery(false);
862878
}
863879
else
864880
{
@@ -892,7 +908,7 @@ private IMongoQuery BuildStringIndexOfQuery(Expression variableExpression, Expre
892908
if (unescapedLength > startIndex + count - index)
893909
{
894910
// substring isn't long enough to match
895-
return _queryBuilder.NotExists("_id"); // matches no documents
911+
return BuildBooleanQuery(false);
896912
}
897913
else
898914
{
@@ -1099,12 +1115,12 @@ private IMongoQuery BuildStringCaseInsensitiveComparisonQuery(Expression variabl
10991115
if (operatorType == ExpressionType.Equal)
11001116
{
11011117
// == "mismatched case" matches no documents
1102-
return _queryBuilder.NotExists("_id");
1118+
return BuildBooleanQuery(false);
11031119
}
11041120
else
11051121
{
11061122
// != "mismatched case" matches all documents
1107-
return new QueryDocument();
1123+
return BuildBooleanQuery(true);
11081124
}
11091125
}
11101126
}
@@ -1265,7 +1281,7 @@ private IMongoQuery BuildTypeComparisonQuery(Expression variableExpression, Expr
12651281
var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType);
12661282
if (discriminator == null)
12671283
{
1268-
return new QueryDocument(); // matches everything
1284+
return BuildBooleanQuery(true);
12691285
}
12701286

12711287
if (discriminator.IsBsonArray)
@@ -1296,7 +1312,7 @@ private IMongoQuery BuildTypeIsQuery(TypeBinaryExpression typeBinaryExpression)
12961312
var discriminator = discriminatorConvention.GetDiscriminator(nominalType, actualType);
12971313
if (discriminator == null)
12981314
{
1299-
return new QueryDocument(); // matches everything
1315+
return BuildBooleanQuery(true);
13001316
}
13011317

13021318
if (discriminator.IsBsonArray)

DriverUnitTests/Linq/SelectQueryTests.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5630,7 +5630,7 @@ where c.S.ToLower() == "Abc"
56305630
Assert.IsNull(selectQuery.Skip);
56315631
Assert.IsNull(selectQuery.Take);
56325632

5633-
Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson());
5633+
Assert.AreEqual("{ \"_id\" : { \"$type\" : -1 } }", selectQuery.BuildQuery().ToJson());
56345634
Assert.AreEqual(0, Consume(query));
56355635
}
56365636

@@ -5722,7 +5722,7 @@ where c.S.ToUpper() == "abc"
57225722
Assert.IsNull(selectQuery.Skip);
57235723
Assert.IsNull(selectQuery.Take);
57245724

5725-
Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson());
5725+
Assert.AreEqual("{ \"_id\" : { \"$type\" : -1 } }", selectQuery.BuildQuery().ToJson());
57265726
Assert.AreEqual(0, Consume(query));
57275727
}
57285728

@@ -5768,7 +5768,7 @@ where c.S.ToUpper() == "Abc"
57685768
Assert.IsNull(selectQuery.Skip);
57695769
Assert.IsNull(selectQuery.Take);
57705770

5771-
Assert.AreEqual("{ \"_id\" : { \"$exists\" : false } }", selectQuery.BuildQuery().ToJson());
5771+
Assert.AreEqual("{ \"_id\" : { \"$type\" : -1 } }", selectQuery.BuildQuery().ToJson());
57725772
Assert.AreEqual(0, Consume(query));
57735773
}
57745774

DriverUnitTestsVB/Linq/SelectQueryTests.vb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5331,7 +5331,7 @@ Namespace MongoDB.DriverUnitTests.Linq
53315331
Assert.IsNull(selectQuery.Skip)
53325332
Assert.IsNull(selectQuery.Take)
53335333

5334-
Assert.AreEqual("{ ""_id"" : { ""$exists"" : false } }", selectQuery.BuildQuery().ToJson())
5334+
Assert.AreEqual("{ ""_id"" : { ""$type"" : -1 } }", selectQuery.BuildQuery().ToJson())
53355335
Assert.AreEqual(0, Consume(query))
53365336
End Sub
53375337

@@ -5421,7 +5421,7 @@ Namespace MongoDB.DriverUnitTests.Linq
54215421
Assert.IsNull(selectQuery.Skip)
54225422
Assert.IsNull(selectQuery.Take)
54235423

5424-
Assert.AreEqual("{ ""_id"" : { ""$exists"" : false } }", selectQuery.BuildQuery().ToJson())
5424+
Assert.AreEqual("{ ""_id"" : { ""$type"" : -1 } }", selectQuery.BuildQuery().ToJson())
54255425
Assert.AreEqual(0, Consume(query))
54265426
End Sub
54275427

@@ -5467,7 +5467,7 @@ Namespace MongoDB.DriverUnitTests.Linq
54675467
Assert.IsNull(selectQuery.Skip)
54685468
Assert.IsNull(selectQuery.Take)
54695469

5470-
Assert.AreEqual("{ ""_id"" : { ""$exists"" : false } }", selectQuery.BuildQuery().ToJson())
5470+
Assert.AreEqual("{ ""_id"" : { ""$type"" : -1 } }", selectQuery.BuildQuery().ToJson())
54715471
Assert.AreEqual(0, Consume(query))
54725472
End Sub
54735473

0 commit comments

Comments
 (0)