diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs
new file mode 100644
index 00000000000..d8419c107aa
--- /dev/null
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Reflection/MqlMethod.cs
@@ -0,0 +1,40 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Reflection;
+
+namespace MongoDB.Driver.Linq.Linq3Implementation.Reflection
+{
+ internal static class MqlMethod
+ {
+ // private static fields
+ private static readonly MethodInfo __exists;
+ private static readonly MethodInfo __isMissing;
+ private static readonly MethodInfo __isNullOrMissing;
+
+ // static constructor
+ static MqlMethod()
+ {
+ __exists = ReflectionInfo.Method((object field) => Mql.Exists(field));
+ __isMissing = ReflectionInfo.Method((object field) => Mql.IsMissing(field));
+ __isNullOrMissing = ReflectionInfo.Method((object field) => Mql.IsNullOrMissing(field));
+ }
+
+ // public properties
+ public static MethodInfo Exists => __exists;
+ public static MethodInfo IsMissing => __isMissing;
+ public static MethodInfo IsNullOrMissing => __isNullOrMissing;
+ }
+}
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs
index d5876619663..55ecb8f3379 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodCallExpressionToAggregationExpressionTranslator.cs
@@ -138,6 +138,10 @@ public static AggregationExpression Translate(TranslationContext context, Method
case "IndexOfAny":
return IndexOfAnyMethodToAggregationExpressionTranslator.Translate(context, expression);
+ case "IsMissing":
+ case "IsNullOrMissing":
+ return IsMissingMethodToAggregationExpressionTranslator.Translate(context, expression);
+
case "Log":
case "Log10":
return LogMethodToAggregationExpressionTranslator.Translate(context, expression);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExistsMethodToAggregationExpressionExpression.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExistsMethodToAggregationExpressionExpression.cs
index 8a4e954e164..ce3370d1a4b 100644
--- a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExistsMethodToAggregationExpressionExpression.cs
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/ExistsMethodToAggregationExpressionExpression.cs
@@ -25,6 +25,11 @@ public static AggregationExpression Translate(TranslationContext context, Method
{
var method = expression.Method;
+ if (method.Is(MqlMethod.Exists))
+ {
+ return IsMissingMethodToAggregationExpressionTranslator.Translate(context, expression);
+ }
+
if (method.Is(ArrayMethod.Exists) || ListMethod.IsExistsMethod(expression.Method))
{
return AnyMethodToAggregationExpressionTranslator.Translate(context, expression);
diff --git a/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslator.cs b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslator.cs
new file mode 100644
index 00000000000..fc5dd265745
--- /dev/null
+++ b/src/MongoDB.Driver/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslator.cs
@@ -0,0 +1,66 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+using System.Linq.Expressions;
+using System.Reflection;
+using MongoDB.Bson;
+using MongoDB.Bson.Serialization.Serializers;
+using MongoDB.Driver.Linq.Linq3Implementation.Ast;
+using MongoDB.Driver.Linq.Linq3Implementation.Ast.Expressions;
+using MongoDB.Driver.Linq.Linq3Implementation.Misc;
+using MongoDB.Driver.Linq.Linq3Implementation.Reflection;
+
+namespace MongoDB.Driver.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
+{
+ internal static class IsMissingMethodToAggregationExpressionTranslator
+ {
+ private static readonly MethodInfo[] __isMissingMethods =
+ {
+ MqlMethod.Exists,
+ MqlMethod.IsMissing,
+ MqlMethod.IsNullOrMissing,
+ };
+
+ public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression)
+ {
+ var method = expression.Method;
+ var arguments = expression.Arguments;
+
+ if (method.IsOneOf(__isMissingMethods))
+ {
+ var fieldExpression = arguments[0];
+ var fieldTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, fieldExpression);
+ var fieldAst = fieldTranslation.Ast;
+ if (fieldAst.NodeType != AstNodeType.GetFieldExpression)
+ {
+ throw new ExpressionNotSupportedException(expression, because: $"argument to {method.Name} must be a reference to a field");
+ }
+
+ var ast = method.Name switch
+ {
+ nameof(Mql.Exists) => AstExpression.Ne(AstExpression.Type(fieldAst), "missing"),
+ nameof(Mql.IsMissing) => AstExpression.Eq(AstExpression.Type(fieldAst), "missing"),
+ nameof(Mql.IsNullOrMissing) => AstExpression.In(AstExpression.Type(fieldAst), new BsonArray { "null", "missing" }),
+ _ => throw new InvalidOperationException("Unexpected method."),
+ };
+
+ return new AggregationExpression(expression, ast, BooleanSerializer.Instance);
+ }
+
+ throw new ExpressionNotSupportedException(expression);
+ }
+ }
+}
diff --git a/src/MongoDB.Driver/Mql.cs b/src/MongoDB.Driver/Mql.cs
new file mode 100644
index 00000000000..abfc8e654bc
--- /dev/null
+++ b/src/MongoDB.Driver/Mql.cs
@@ -0,0 +1,58 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System;
+
+namespace MongoDB.Driver
+{
+ ///
+ /// Contains methods that can be used to access MongoDB specific functionality in LINQ queries.
+ ///
+ public static class Mql
+ {
+ ///
+ /// Tests whether a field exists.
+ ///
+ /// The type of the field.
+ /// The field.
+ /// true if the field exists.
+ public static bool Exists(TField field)
+ {
+ throw new NotSupportedException("This method is not functional. It is only usable in MongoDB LINQ queries.");
+ }
+
+ ///
+ /// Tests whether a field is missing.
+ ///
+ /// The type of the field.
+ /// The field.
+ /// true if the field is missing.
+ public static bool IsMissing(TField field)
+ {
+ throw new NotSupportedException("This method is not functional. It is only usable in MongoDB LINQ queries.");
+ }
+
+ ///
+ /// Tests whether a field is null or missing.
+ ///
+ /// The type of the field.
+ /// The field.
+ /// true if the field is null or missing.
+ public static bool IsNullOrMissing(TField field)
+ {
+ throw new NotSupportedException("This method is not functional. It is only usable in MongoDB LINQ queries.");
+ }
+ }
+}
diff --git a/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslatorTests.cs b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslatorTests.cs
new file mode 100644
index 00000000000..017f64f66e4
--- /dev/null
+++ b/tests/MongoDB.Driver.Tests/Linq/Linq3Implementation/Translators/ExpressionToAggregationExpressionTranslators/MethodTranslators/IsMissingMethodToAggregationExpressionTranslatorTests.cs
@@ -0,0 +1,88 @@
+/* Copyright 2010-present MongoDB Inc.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+using System.Linq;
+using FluentAssertions;
+using MongoDB.Bson;
+using MongoDB.Driver.Linq;
+using Xunit;
+
+namespace MongoDB.Driver.Tests.Linq.Linq3Implementation.Translators.ExpressionToAggregationExpressionTranslators.MethodTranslators
+{
+ public class IsMissingMethodToAggregationExpressionTranslatorTests : Linq3IntegrationTest
+ {
+ [Fact]
+ public void Select_Exists_should_work()
+ {
+ var collection = GetCollection();
+
+ var queryable = collection.AsQueryable()
+ .Select(x => Mql.Exists(x.S));
+
+ var stages = Translate(collection, queryable);
+ AssertStages(stages, "{ $project : { _v : { $ne : [{ $type : '$S' }, 'missing'] }, _id : 0 } }");
+
+ var results = queryable.ToList();
+ results.Should().Equal(false, true, true);
+ }
+
+ [Fact]
+ public void Select_IsMissing_should_work()
+ {
+ var collection = GetCollection();
+
+ var queryable = collection.AsQueryable()
+ .Select(x => Mql.IsMissing(x.S));
+
+ var stages = Translate(collection, queryable);
+ AssertStages(stages, "{ $project : { _v : { $eq : [{ $type : '$S' }, 'missing'] }, _id : 0 } }");
+
+ var results = queryable.ToList();
+ results.Should().Equal(true, false, false);
+ }
+
+ [Fact]
+ public void Select_IsNullOrMissing_should_work()
+ {
+ var collection = GetCollection();
+
+ var queryable = collection.AsQueryable()
+ .Select(x => Mql.IsNullOrMissing(x.S));
+
+ var stages = Translate(collection, queryable);
+ AssertStages(stages, "{ $project : { _v : { $in : [{ $type : '$S' }, ['null', 'missing']] }, _id : 0 } }");
+
+ var results = queryable.ToList();
+ results.Should().Equal(true, true, false);
+ }
+
+ private IMongoCollection GetCollection()
+ {
+ var collection = GetCollection("test");
+ CreateCollection(
+ GetCollection("test"),
+ BsonDocument.Parse("{ _id : 1 }"),
+ BsonDocument.Parse("{ _id : 2, S : null }"),
+ BsonDocument.Parse("{ _id : 3, S : 'abc' }"));
+ return collection;
+ }
+
+ private class C
+ {
+ public int Id { get; set; }
+ public string S { get; set; }
+ }
+ }
+}