diff --git a/src/mongo/db/cst/cst_match_translation.cpp b/src/mongo/db/cst/cst_match_translation.cpp
index f8ee19e562..288217732f 100644
--- a/src/mongo/db/cst/cst_match_translation.cpp
+++ b/src/mongo/db/cst/cst_match_translation.cpp
@@ -103,7 +103,7 @@ std::unique_ptr<MatchExpression> translateExists(const CNode::Fieldname& fieldNa
             argument.payload)) {
         return root;
     }
-    return std::make_unique<NotMatchExpression>(root.release());
+    return std::make_unique<NotMatchExpression>(std::move(root));
 }
 
 MatcherTypeSet getMatcherTypeSet(const CNode& argument) {
diff --git a/src/mongo/db/matcher/expression_array.cpp b/src/mongo/db/matcher/expression_array.cpp
index cbff0adf1c..79b51f37a6 100644
--- a/src/mongo/db/matcher/expression_array.cpp
+++ b/src/mongo/db/matcher/expression_array.cpp
@@ -68,8 +68,8 @@ bool ArrayMatchingMatchExpression::equivalent(const MatchExpression* other) cons
 
 ElemMatchObjectMatchExpression::ElemMatchObjectMatchExpression(
     StringData path, std::unique_ptr<MatchExpression> sub, clonable_ptr<ErrorAnnotation> annotation)
-    : ArrayMatchingMatchExpression(ELEM_MATCH_OBJECT, path, std::move(annotation)),
-      _sub(std::move(sub)) {}
+    : ArrayMatchingMatchExpression(ELEM_MATCH_OBJECT, path, std::move(annotation)), _children(1)
+    { _children[0] = std::move(sub); }
 
 bool ElemMatchObjectMatchExpression::matchesArray(const BSONObj& anArray,
                                                   MatchDetails* details) const {
@@ -78,7 +78,7 @@ bool ElemMatchObjectMatchExpression::matchesArray(const BSONObj& anArray,
         BSONElement inner = i.next();
         if (!inner.isABSONObj())
             continue;
-        if (_sub->matchesBSON(inner.Obj(), nullptr)) {
+        if (_children[0]->matchesBSON(inner.Obj(), nullptr)) {
             if (details && details->needRecord()) {
                 details->setElemMatchKey(inner.fieldName());
             }
@@ -98,19 +98,19 @@ void ElemMatchObjectMatchExpression::debugString(StringBuilder& debug, int inden
         td->debugString(&debug);
     }
     debug << "\n";
-    _sub->debugString(debug, indentationLevel + 1);
+    _children[0]->debugString(debug, indentationLevel + 1);
 }
 
 BSONObj ElemMatchObjectMatchExpression::getSerializedRightHandSide() const {
     BSONObjBuilder subBob;
-    _sub->serialize(&subBob, true);
+    _children[0]->serialize(&subBob, true);
     return BSON("$elemMatch" << subBob.obj());
 }
 
 MatchExpression::ExpressionOptimizerFunc ElemMatchObjectMatchExpression::getOptimizer() const {
     return [](std::unique_ptr<MatchExpression> expression) {
         auto& elemExpression = static_cast<ElemMatchObjectMatchExpression&>(*expression);
-        elemExpression._sub = MatchExpression::optimize(std::move(elemExpression._sub));
+        elemExpression._children[0] = MatchExpression::optimize(std::move(elemExpression._children[0]));
 
         return expression;
     };
@@ -121,14 +121,14 @@ MatchExpression::ExpressionOptimizerFunc ElemMatchObjectMatchExpression::getOpti
 ElemMatchValueMatchExpression::ElemMatchValueMatchExpression(
     StringData path, std::unique_ptr<MatchExpression> sub, clonable_ptr<ErrorAnnotation> annotation)
     : ArrayMatchingMatchExpression(ELEM_MATCH_VALUE, path, std::move(annotation)),
-      _subs(makeVector(std::move(sub))) {}
+      _children(makeVector(std::move(sub))) {}
 
 ElemMatchValueMatchExpression::ElemMatchValueMatchExpression(
     StringData path, clonable_ptr<ErrorAnnotation> annotation)
     : ArrayMatchingMatchExpression(ELEM_MATCH_VALUE, path, std::move(annotation)) {}
 
 void ElemMatchValueMatchExpression::add(std::unique_ptr<MatchExpression> sub) {
-    _subs.push_back(std::move(sub));
+    _children.push_back(std::move(sub));
 }
 
 bool ElemMatchValueMatchExpression::matchesArray(const BSONObj& anArray,
@@ -148,8 +148,8 @@ bool ElemMatchValueMatchExpression::matchesArray(const BSONObj& anArray,
 }
 
 bool ElemMatchValueMatchExpression::_arrayElementMatchesAll(const BSONElement& e) const {
-    for (unsigned i = 0; i < _subs.size(); i++) {
-        if (!_subs[i]->matchesSingleElement(e))
+    for (unsigned i = 0; i < _children.size(); i++) {
+        if (!_children[i]->matchesSingleElement(e))
             return false;
     }
     return true;
@@ -165,15 +165,15 @@ void ElemMatchValueMatchExpression::debugString(StringBuilder& debug, int indent
         td->debugString(&debug);
     }
     debug << "\n";
-    for (unsigned i = 0; i < _subs.size(); i++) {
-        _subs[i]->debugString(debug, indentationLevel + 1);
+    for (unsigned i = 0; i < _children.size(); i++) {
+        _children[i]->debugString(debug, indentationLevel + 1);
     }
 }
 
 BSONObj ElemMatchValueMatchExpression::getSerializedRightHandSide() const {
     BSONObjBuilder emBob;
 
-    for (auto&& child : _subs) {
+    for (auto&& child : _children) {
         child->serialize(&emBob, false);
     }
 
@@ -182,7 +182,7 @@ BSONObj ElemMatchValueMatchExpression::getSerializedRightHandSide() const {
 
 MatchExpression::ExpressionOptimizerFunc ElemMatchValueMatchExpression::getOptimizer() const {
     return [](std::unique_ptr<MatchExpression> expression) {
-        auto& subs = static_cast<ElemMatchValueMatchExpression&>(*expression)._subs;
+        auto& subs = static_cast<ElemMatchValueMatchExpression&>(*expression)._children;
 
         for (auto& subExpression : subs)
             subExpression = MatchExpression::optimize(std::move(subExpression));
diff --git a/src/mongo/db/matcher/expression_array.h b/src/mongo/db/matcher/expression_array.h
index 16637c2b37..c33cad03f2 100644
--- a/src/mongo/db/matcher/expression_array.h
+++ b/src/mongo/db/matcher/expression_array.h
@@ -81,7 +81,7 @@ public:
     virtual std::unique_ptr<MatchExpression> shallowClone() const {
         std::unique_ptr<ElemMatchObjectMatchExpression> e =
             std::make_unique<ElemMatchObjectMatchExpression>(
-                path(), _sub->shallowClone(), _errorAnnotation);
+                path(), _children[0]->shallowClone(), _errorAnnotation);
         if (getTag()) {
             e->setTag(getTag()->clone());
         }
@@ -93,7 +93,7 @@ public:
     BSONObj getSerializedRightHandSide() const final;
 
     const std::vector<std::unique_ptr<MatchExpression>>* getChildVector() const final {
-        return nullptr;
+        return &_children;
     }
 
     virtual size_t numChildren() const {
@@ -101,15 +101,15 @@ public:
     }
 
     virtual MatchExpression* getChild(size_t i) const {
-        return _sub.get();
+        return _children[0].get();
     }
 
     std::unique_ptr<MatchExpression> releaseChild() {
-        return std::move(_sub);
+        return std::move(_children[0]);
     }
 
     void resetChild(std::unique_ptr<MatchExpression> newChild) {
-        _sub = std::move(newChild);
+        _children[0] = std::move(newChild);
     }
 
     void acceptVisitor(MatchExpressionMutableVisitor* visitor) final {
@@ -123,7 +123,7 @@ public:
 private:
     ExpressionOptimizerFunc getOptimizer() const final;
 
-    std::unique_ptr<MatchExpression> _sub;
+    std::vector<std::unique_ptr<MatchExpression>> _children;
 };
 
 class ElemMatchValueMatchExpression final : public ArrayMatchingMatchExpression {
@@ -141,8 +141,8 @@ public:
     virtual std::unique_ptr<MatchExpression> shallowClone() const {
         std::unique_ptr<ElemMatchValueMatchExpression> e =
             std::make_unique<ElemMatchValueMatchExpression>(path(), _errorAnnotation);
-        for (size_t i = 0; i < _subs.size(); ++i) {
-            e->add(_subs[i]->shallowClone());
+        for (size_t i = 0; i < _children.size(); ++i) {
+            e->add(_children[i]->shallowClone());
         }
         if (getTag()) {
             e->setTag(getTag()->clone());
@@ -155,15 +155,15 @@ public:
     BSONObj getSerializedRightHandSide() const final;
 
     const std::vector<std::unique_ptr<MatchExpression>>* getChildVector() const final {
-        return &_subs;
+        return &_children;
     }
 
     virtual size_t numChildren() const {
-        return _subs.size();
+        return _children.size();
     }
 
     virtual MatchExpression* getChild(size_t i) const {
-        return _subs[i].get();
+        return _children[i].get();
     }
 
     void acceptVisitor(MatchExpressionMutableVisitor* visitor) final {
@@ -179,7 +179,7 @@ private:
 
     bool _arrayElementMatchesAll(const BSONElement& e) const;
 
-    std::vector<std::unique_ptr<MatchExpression>> _subs;
+    std::vector<std::unique_ptr<MatchExpression>> _children;
 };
 
 class SizeMatchExpression : public ArrayMatchingMatchExpression {
diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp
index 984e28ca32..6eb47a7ed4 100644
--- a/src/mongo/db/matcher/expression_parser.cpp
+++ b/src/mongo/db/matcher/expression_parser.cpp
@@ -1431,7 +1431,7 @@ StatusWithMatchExpression parseNot(StringData name,
             return regex;
         }
         return {std::make_unique<NotMatchExpression>(
-            regex.getValue().release(),
+            std::move(regex.getValue()),
             doc_validation_error::createAnnotation(expCtx, "$not", BSONObj()))};
     }
 
@@ -1459,7 +1459,7 @@ StatusWithMatchExpression parseNot(StringData name,
     }
 
     return {std::make_unique<NotMatchExpression>(
-        theAnd.release(), doc_validation_error::createAnnotation(expCtx, "$not", BSONObj()))};
+        std::move(theAnd), doc_validation_error::createAnnotation(expCtx, "$not", BSONObj()))};
 }
 
 StatusWithMatchExpression parseInternalSchemaBinDataSubType(
@@ -1587,7 +1587,7 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
             disableSBEForNumericPathComponent(expCtx, s.getValue()->fieldRef());
 
             return {std::make_unique<NotMatchExpression>(
-                s.getValue().release(),
+                std::move(s.getValue()),
                 doc_validation_error::createAnnotation(expCtx, AnnotationMode::kIgnoreButDescend))};
         }
         case PathAcceptingKeyword::EQUALITY:
@@ -1634,7 +1634,7 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
             // numeric path component instead.
             disableSBEForNumericPathComponent(expCtx, temp->fieldRef());
             return {std::make_unique<NotMatchExpression>(
-                temp.release(),
+                std::move(temp),
                 doc_validation_error::createAnnotation(expCtx, AnnotationMode::kIgnoreButDescend))};
         }
 
@@ -1683,7 +1683,7 @@ StatusWithMatchExpression parseSubField(const BSONObj& context,
             }
 
             return {std::make_unique<NotMatchExpression>(
-                existsExpr.release(),
+                std::move(existsExpr),
                 doc_validation_error::createAnnotation(expCtx, AnnotationMode::kIgnoreButDescend))};
         }
 
diff --git a/src/mongo/db/matcher/expression_serialization_test.cpp b/src/mongo/db/matcher/expression_serialization_test.cpp
index 78517a5263..7e68703b06 100644
--- a/src/mongo/db/matcher/expression_serialization_test.cpp
+++ b/src/mongo/db/matcher/expression_serialization_test.cpp
@@ -1097,7 +1097,7 @@ TEST(SerializeBasic, ExpressionNotWithDirectPathExpSerializesCorrectly) {
     auto equalityRHSElem = originalBSON["a"]["$not"]["$eq"];
     auto equalityExpression = std::make_unique<EqualityMatchExpression>("a"_sd, equalityRHSElem);
 
-    auto notExpression = std::make_unique<NotMatchExpression>(equalityExpression.release());
+    auto notExpression = std::make_unique<NotMatchExpression>(std::move(equalityExpression));
     Matcher reserialized(serialize(notExpression.get()),
                          expCtx,
                          ExtensionsCallbackNoop(),
@@ -1118,8 +1118,8 @@ TEST(SerializeBasic, ExpressionNotNotDirectlySerializesCorrectly) {
     auto equalityRHSElem = originalBSON["a"]["$not"]["$not"]["$eq"];
     auto equalityExpression = std::make_unique<EqualityMatchExpression>("a"_sd, equalityRHSElem);
 
-    auto nestedNot = std::make_unique<NotMatchExpression>(equalityExpression.release());
-    auto topNot = std::make_unique<NotMatchExpression>(nestedNot.release());
+    auto nestedNot = std::make_unique<NotMatchExpression>(std::move(equalityExpression));
+    auto topNot = std::make_unique<NotMatchExpression>(std::move(nestedNot));
     Matcher reserialized(serialize(topNot.get()),
                          expCtx,
                          ExtensionsCallbackNoop(),
diff --git a/src/mongo/db/matcher/expression_tree.cpp b/src/mongo/db/matcher/expression_tree.cpp
index ec7a5e08dd..c5f1c44d27 100644
--- a/src/mongo/db/matcher/expression_tree.cpp
+++ b/src/mongo/db/matcher/expression_tree.cpp
@@ -42,29 +42,33 @@
 namespace mongo {
 
 void ListOfMatchExpression::_debugList(StringBuilder& debug, int indentationLevel) const {
-    for (unsigned i = 0; i < _expressions.size(); i++)
-        _expressions[i]->debugString(debug, indentationLevel + 1);
+    for (unsigned i = 0; i < _children.size(); i++)
+        _children[i]->debugString(debug, indentationLevel + 1);
 }
 
 void ListOfMatchExpression::_listToBSON(BSONArrayBuilder* out, bool includePath) const {
-    for (unsigned i = 0; i < _expressions.size(); i++) {
+    for (unsigned i = 0; i < _children.size(); i++) {
         BSONObjBuilder childBob(out->subobjStart());
-        _expressions[i]->serialize(&childBob, includePath);
+        _children[i]->serialize(&childBob, includePath);
     }
     out->doneFast();
 }
 
 MatchExpression::ExpressionOptimizerFunc ListOfMatchExpression::getOptimizer() const {
     return [](std::unique_ptr<MatchExpression> expression) -> std::unique_ptr<MatchExpression> {
-        auto& children = static_cast<ListOfMatchExpression&>(*expression)._expressions;
+        auto& children = static_cast<ListOfMatchExpression&>(*expression)._children;
 
         // Recursively apply optimizations to child expressions.
         for (auto& childExpression : children)
             childExpression = MatchExpression::optimize(std::move(childExpression));
 
+        MatchType matchType = expression->matchType();
+        if (matchType == NOT) {
+            return expression;
+        }
+
         // Associativity of AND and OR: an AND absorbs the children of any ANDs among its children
         // (and likewise for any OR with OR children).
-        MatchType matchType = expression->matchType();
         if (matchType == AND || matchType == OR) {
             auto absorbedExpressions = std::vector<std::unique_ptr<MatchExpression>>{};
             for (auto& childExpression : children) {
@@ -77,7 +81,7 @@ MatchExpression::ExpressionOptimizerFunc ListOfMatchExpression::getOptimizer() c
                     // Move all of the grandchildren from the child expression to
                     // absorbedExpressions.
                     auto& grandChildren =
-                        static_cast<ListOfMatchExpression&>(*childExpressionPtr)._expressions;
+                        static_cast<ListOfMatchExpression&>(*childExpressionPtr)._children;
                     std::move(grandChildren.begin(),
                               grandChildren.end(),
                               std::back_inserter(absorbedExpressions));
@@ -296,14 +300,18 @@ bool ListOfMatchExpression::equivalent(const MatchExpression* other) const {
     if (matchType() != other->matchType())
         return false;
 
+    if (matchType() == NOT) {
+        return getChild(0)->equivalent(other->getChild(0));
+    }
+
     const ListOfMatchExpression* realOther = static_cast<const ListOfMatchExpression*>(other);
 
-    if (_expressions.size() != realOther->_expressions.size())
+    if (_children.size() != realOther->_children.size())
         return false;
 
     // TOOD: order doesn't matter
-    for (unsigned i = 0; i < _expressions.size(); i++)
-        if (!_expressions[i]->equivalent(realOther->_expressions[i].get()))
+    for (unsigned i = 0; i < _children.size(); i++)
+        if (!_children[i]->equivalent(realOther->_children[i].get()))
             return false;
 
     return true;
@@ -440,7 +448,7 @@ void NorMatchExpression::serialize(BSONObjBuilder* out, bool includePath) const
 void NotMatchExpression::debugString(StringBuilder& debug, int indentationLevel) const {
     _debugAddSpace(debug, indentationLevel);
     debug << "$not\n";
-    _exp->debugString(debug, indentationLevel + 1);
+    getChild(0)->debugString(debug, indentationLevel + 1);
 }
 
 void NotMatchExpression::serializeNotExpressionToNor(MatchExpression* exp,
@@ -456,7 +464,7 @@ void NotMatchExpression::serializeNotExpressionToNor(MatchExpression* exp,
 }
 
 void NotMatchExpression::serialize(BSONObjBuilder* out, bool includePath) const {
-    if (_exp->matchType() == MatchType::AND && _exp->numChildren() == 0) {
+    if (getChild(0)->matchType() == MatchType::AND && getChild(0)->numChildren() == 0) {
         out->append("$alwaysFalse", 1);
         return;
     }
@@ -466,19 +474,19 @@ void NotMatchExpression::serialize(BSONObjBuilder* out, bool includePath) const
         // Our parser does not accept a $and directly within a $not, instead expecting the direct
         // notation like {x: {$not: {$gt: 5, $lt: 0}}}. We represent such an expression with an AND
         // internally, so we un-nest it here to be able to re-parse it.
-        if (_exp->matchType() == MatchType::AND) {
-            for (size_t x = 0; x < _exp->numChildren(); ++x) {
-                _exp->getChild(x)->serialize(&notBob, includePath);
+        if (getChild(0)->matchType() == MatchType::AND) {
+            for (size_t x = 0; x < getChild(0)->numChildren(); ++x) {
+                getChild(0)->getChild(x)->serialize(&notBob, includePath);
             }
         } else {
-            _exp->serialize(&notBob, includePath);
+            getChild(0)->serialize(&notBob, includePath);
         }
         return;
     }
 
-    auto expressionToNegate = _exp.get();
-    if (_exp->matchType() == MatchType::AND && _exp->numChildren() == 1) {
-        expressionToNegate = _exp->getChild(0);
+    auto expressionToNegate = getChild(0);
+    if (getChild(0)->matchType() == MatchType::AND && getChild(0)->numChildren() == 1) {
+        expressionToNegate = getChild(0)->getChild(0);
     }
 
     // It is generally easier to be correct if we just always serialize to a $nor, since this will
@@ -499,21 +507,4 @@ void NotMatchExpression::serialize(BSONObjBuilder* out, bool includePath) const
     }
     return serializeNotExpressionToNor(expressionToNegate, out, includePath);
 }
-
-bool NotMatchExpression::equivalent(const MatchExpression* other) const {
-    if (matchType() != other->matchType())
-        return false;
-
-    return _exp->equivalent(other->getChild(0));
-}
-
-
-MatchExpression::ExpressionOptimizerFunc NotMatchExpression::getOptimizer() const {
-    return [](std::unique_ptr<MatchExpression> expression) {
-        auto& notExpression = static_cast<NotMatchExpression&>(*expression);
-        notExpression._exp = MatchExpression::optimize(std::move(notExpression._exp));
-
-        return expression;
-    };
-}
 }  // namespace mongo
diff --git a/src/mongo/db/matcher/expression_tree.h b/src/mongo/db/matcher/expression_tree.h
index 54594a6d3d..4cf07169f2 100644
--- a/src/mongo/db/matcher/expression_tree.h
+++ b/src/mongo/db/matcher/expression_tree.h
@@ -46,42 +46,42 @@ public:
     ListOfMatchExpression(MatchType type,
                           clonable_ptr<ErrorAnnotation> annotation,
                           std::vector<std::unique_ptr<MatchExpression>> expressions)
-        : MatchExpression(type, std::move(annotation)), _expressions(std::move(expressions)) {}
+        : MatchExpression(type, std::move(annotation)), _children(std::move(expressions)) {}
 
     void add(std::unique_ptr<MatchExpression> e) {
-        _expressions.push_back(std::move(e));
+        _children.push_back(std::move(e));
     }
 
     void clear() {
-        _expressions.clear();
+        _children.clear();
     }
 
     virtual size_t numChildren() const {
-        return _expressions.size();
+        return _children.size();
     }
 
     MatchExpression* getChild(size_t i) const final {
-        return _expressions[i].get();
+        return _children[i].get();
     }
 
     /*
      * Replaces the ith child with nullptr, and releases ownership of the child.
      */
     std::unique_ptr<MatchExpression> releaseChild(size_t i) {
-        return std::move(_expressions[i]);
+        return std::move(_children[i]);
     }
 
     /*
      * Removes the ith child, and releases ownership of the child.
      */
     virtual std::unique_ptr<MatchExpression> removeChild(size_t i) {
-        auto child = std::move(_expressions[i]);
-        _expressions.erase(_expressions.begin() + i);
+        auto child = std::move(_children[i]);
+        _children.erase(_children.begin() + i);
         return child;
     }
 
     const std::vector<std::unique_ptr<MatchExpression>>* getChildVector() const final {
-        return &_expressions;
+        return &_children;
     }
 
     bool equivalent(const MatchExpression* other) const final;
@@ -98,7 +98,7 @@ protected:
 private:
     ExpressionOptimizerFunc getOptimizer() const final;
 
-    std::vector<std::unique_ptr<MatchExpression>> _expressions;
+    std::vector<std::unique_ptr<MatchExpression>> _children;
 };
 
 class AndMatchExpression : public ListOfMatchExpression {
@@ -231,19 +231,15 @@ public:
     }
 };
 
-class NotMatchExpression final : public MatchExpression {
+class NotMatchExpression final : public ListOfMatchExpression {
 public:
-    explicit NotMatchExpression(MatchExpression* e,
-                                clonable_ptr<ErrorAnnotation> annotation = nullptr)
-        : MatchExpression(NOT, std::move(annotation)), _exp(e) {}
-
     explicit NotMatchExpression(std::unique_ptr<MatchExpression> expr,
                                 clonable_ptr<ErrorAnnotation> annotation = nullptr)
-        : MatchExpression(NOT, std::move(annotation)), _exp(std::move(expr)) {}
+        : ListOfMatchExpression(NOT, std::move(annotation), makeVector(std::move(expr))) {}
 
     virtual std::unique_ptr<MatchExpression> shallowClone() const {
         std::unique_ptr<NotMatchExpression> self =
-            std::make_unique<NotMatchExpression>(_exp->shallowClone(), _errorAnnotation);
+            std::make_unique<NotMatchExpression>(getChild(0)->shallowClone(), _errorAnnotation);
         if (getTag()) {
             self->setTag(getTag()->clone());
         }
@@ -251,43 +247,17 @@ public:
     }
 
     bool matches(const MatchableDocument* doc, MatchDetails* details = nullptr) const final {
-        return !_exp->matches(doc, nullptr);
+        return !getChild(0)->matches(doc, nullptr);
     }
 
     bool matchesSingleElement(const BSONElement& elt, MatchDetails* details = nullptr) const final {
-        return !_exp->matchesSingleElement(elt, details);
+        return !getChild(0)->matchesSingleElement(elt, details);
     }
 
     virtual void debugString(StringBuilder& debug, int indentationLevel = 0) const;
 
     virtual void serialize(BSONObjBuilder* out, bool includePath) const;
 
-    bool equivalent(const MatchExpression* other) const final;
-
-    size_t numChildren() const final {
-        return 1;
-    }
-
-    MatchExpression* getChild(size_t i) const final {
-        return _exp.get();
-    }
-
-    const std::vector<std::unique_ptr<MatchExpression>>* getChildVector() const final {
-        return nullptr;
-    }
-
-    MatchExpression* releaseChild() {
-        return _exp.release();
-    }
-
-    void resetChild(MatchExpression* newChild) {
-        _exp.reset(newChild);
-    }
-
-    MatchCategory getCategory() const final {
-        return MatchCategory::kLogical;
-    }
-
     void acceptVisitor(MatchExpressionMutableVisitor* visitor) final {
         visitor->visit(this);
     }
@@ -300,9 +270,5 @@ private:
     static void serializeNotExpressionToNor(MatchExpression* exp,
                                             BSONObjBuilder* out,
                                             bool includePath);
-
-    ExpressionOptimizerFunc getOptimizer() const final;
-
-    std::unique_ptr<MatchExpression> _exp;
 };
 }  // namespace mongo
diff --git a/src/mongo/db/matcher/expression_tree_test.cpp b/src/mongo/db/matcher/expression_tree_test.cpp
index 16c03b3133..a90d14525f 100644
--- a/src/mongo/db/matcher/expression_tree_test.cpp
+++ b/src/mongo/db/matcher/expression_tree_test.cpp
@@ -43,7 +43,7 @@ namespace mongo {
 TEST(NotMatchExpression, MatchesScalar) {
     auto baseOperand = BSON("$lt" << 5);
     auto lt = std::make_unique<LTMatchExpression>("a", baseOperand["$lt"]);
-    auto notOp = NotMatchExpression{lt.release()};
+    auto notOp = NotMatchExpression{std::move(lt)};
     ASSERT(notOp.matchesBSON(BSON("a" << 6), nullptr));
     ASSERT(!notOp.matchesBSON(BSON("a" << 4), nullptr));
 }
@@ -51,7 +51,7 @@ TEST(NotMatchExpression, MatchesScalar) {
 TEST(NotMatchExpression, MatchesArray) {
     auto baseOperand = BSON("$lt" << 5);
     auto lt = std::make_unique<LTMatchExpression>("a", baseOperand["$lt"]);
-    auto notOp = NotMatchExpression{lt.release()};
+    auto notOp = NotMatchExpression{std::move(lt)};
     ASSERT(notOp.matchesBSON(BSON("a" << BSON_ARRAY(6)), nullptr));
     ASSERT(!notOp.matchesBSON(BSON("a" << BSON_ARRAY(4)), nullptr));
     // All array elements must match.
@@ -61,7 +61,7 @@ TEST(NotMatchExpression, MatchesArray) {
 TEST(NotMatchExpression, ElemMatchKey) {
     auto baseOperand = BSON("$lt" << 5);
     auto lt = std::make_unique<LTMatchExpression>("a", baseOperand["$lt"]);
-    auto notOp = NotMatchExpression{lt.release()};
+    auto notOp = NotMatchExpression{std::move(lt)};
     auto details = MatchDetails{};
     details.requestElemMatchKey();
     ASSERT(!notOp.matchesBSON(BSON("a" << BSON_ARRAY(1)), &details));
@@ -77,7 +77,7 @@ TEST(NotMatchExpression, SetCollatorPropagatesToChild) {
     auto baseOperand = BSON("a"
                             << "string");
     auto eq = std::make_unique<EqualityMatchExpression>("a", baseOperand["a"]);
-    auto notOp = NotMatchExpression{eq.release()};
+    auto notOp = NotMatchExpression{std::move(eq)};
     auto collator = CollatorInterfaceMock{CollatorInterfaceMock::MockType::kAlwaysEqual};
     notOp.setCollator(&collator);
     ASSERT(!notOp.matchesBSON(BSON("a"
@@ -122,7 +122,7 @@ TEST(AndOp, MatchesElementThreeClauses) {
 TEST(AndOp, MatchesSingleClause) {
     auto baseOperand = BSON("$ne" << 5);
     auto eq = std::make_unique<EqualityMatchExpression>("a", baseOperand["$ne"]);
-    auto ne = std::make_unique<NotMatchExpression>(eq.release());
+    auto ne = std::make_unique<NotMatchExpression>(std::move(eq));
 
     auto andOp = AndMatchExpression{};
     andOp.add(std::move(ne));
@@ -185,7 +185,7 @@ TEST(OrOp, NoClauses) {
 TEST(OrOp, MatchesSingleClause) {
     auto baseOperand = BSON("$ne" << 5);
     auto eq = std::make_unique<EqualityMatchExpression>("a", baseOperand["$ne"]);
-    auto ne = std::make_unique<NotMatchExpression>(eq.release());
+    auto ne = std::make_unique<NotMatchExpression>(std::move(eq));
 
     auto orOp = OrMatchExpression{};
     orOp.add(std::move(ne));
@@ -278,7 +278,7 @@ TEST(NorOp, NoClauses) {
 TEST(NorOp, MatchesSingleClause) {
     auto baseOperand = BSON("$ne" << 5);
     auto eq = std::make_unique<EqualityMatchExpression>("a", baseOperand["$ne"]);
-    auto ne = std::make_unique<NotMatchExpression>(eq.release());
+    auto ne = std::make_unique<NotMatchExpression>(std::move(eq));
 
     auto norOp = NorMatchExpression{};
     norOp.add(std::move(ne));
