The $expr comparison queries have the different semantics as the same comparison queries in a find query. Consider the following two queries and one document w/o the field 'missing',
$expr Query: db.test.find({$expr: { $lt : ["$missing", "r"] }})
find Query: db.test.find({"$missing": { $lt: "r" }})
Document with missing field: {a:1}
The $expr Query uses the aggregate expression to evaluate the comparison. The agg expression will evaluate $missing to null and still apply the comparison (null < “r”). So the expression is "true" and the document {a: 1} is returned. The find query applies type bracketing on field "missing", documents w/o the 'missing' field will not be evaluated in the comparison at all. These are both expected behaviors in MQL.
However, the use of a sparse index in the same $expr query can cause returning incomplete results, because a sparse index does not index missing field or the document that does not have any indexed field. Take the same $expr example above, if a sparse index ({"$missing": 1} {sparse: true}) was used to answer {$expr: { $lt : ["$missing", "r"] }}, document {a: 1} is not indexed and will not be compared either, which is supposed to be returned by the semantics of the $expr query.