|
45 | 45 | #include "mongo/util/assert_util.h"
|
46 | 46 | #include "mongo/util/intrusive_counter.h"
|
47 | 47 |
|
| 48 | +#include "mongo/db/pipeline/document_source_match.h" |
| 49 | +#include "mongo/db/pipeline/document_source_single_document_transformation.h" |
| 50 | +#include "mongo/db/pipeline/semantic_analysis.h" |
| 51 | + |
48 | 52 | namespace mongo {
|
49 | 53 |
|
50 | 54 | constexpr StringData DocumentSourceGroup::kStageName;
|
@@ -82,6 +86,88 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBson(
|
82 | 86 | return createFromBsonWithMaxMemoryUsage(std::move(elem), expCtx, boost::none);
|
83 | 87 | }
|
84 | 88 |
|
| 89 | +Pipeline::SourceContainer::iterator DocumentSourceGroup::doOptimizeAt( |
| 90 | + Pipeline::SourceContainer::iterator itr, Pipeline::SourceContainer* container) { |
| 91 | + invariant(*itr == this); |
| 92 | + |
| 93 | + if (pushDotRenamedMatch(itr, container)) { |
| 94 | + return itr; |
| 95 | + } |
| 96 | + |
| 97 | + return std::next(itr); |
| 98 | +} |
| 99 | + |
| 100 | +bool DocumentSourceGroup::pushDotRenamedMatch(Pipeline::SourceContainer::iterator itr, |
| 101 | + Pipeline::SourceContainer* container) { |
| 102 | + if (std::next(itr) == container->end() || std::next(std::next(itr)) == container->end()) { |
| 103 | + return false; |
| 104 | + } |
| 105 | + |
| 106 | + // Keep separate iterators for each stage (projection, match). |
| 107 | + auto prospectiveProjectionItr = std::next(itr); |
| 108 | + auto prospectiveProjection = |
| 109 | + dynamic_cast<DocumentSourceSingleDocumentTransformation*>(prospectiveProjectionItr->get()); |
| 110 | + |
| 111 | + auto prospectiveMatchItr = std::next(std::next(itr)); |
| 112 | + auto prospectiveMatch = dynamic_cast<DocumentSourceMatch*>(prospectiveMatchItr->get()); |
| 113 | + |
| 114 | + if (!prospectiveProjection || !prospectiveMatch) { |
| 115 | + return false; |
| 116 | + } |
| 117 | + |
| 118 | + stdx::unordered_set<std::string> groupingFields; |
| 119 | + StringMap<std::string> relevantRenames; |
| 120 | + |
| 121 | + auto itsGroup = dynamic_cast<DocumentSourceGroup*>(itr->get()); |
| 122 | + |
| 123 | + auto idFields = itsGroup->getIdFields(); |
| 124 | + for (auto& idFieldsItr : idFields) { |
| 125 | + groupingFields.insert(idFieldsItr.first); |
| 126 | + } |
| 127 | + |
| 128 | + GetModPathsReturn paths = prospectiveProjection->getModifiedPaths(); |
| 129 | + |
| 130 | + for (const auto& thisComplexRename : paths.complexRenames) { |
| 131 | + |
| 132 | + // Check if the dotted renaming is done on a grouping field. |
| 133 | + // This ensures that the top level is flat i.e., no arrays. |
| 134 | + if (groupingFields.find(thisComplexRename.second) != groupingFields.end()) { |
| 135 | + relevantRenames.insert(std::pair<std::string, std::string>(thisComplexRename.first, |
| 136 | + thisComplexRename.second)); |
| 137 | + } |
| 138 | + } |
| 139 | + |
| 140 | + // Perform all changes on a copy of the match source. |
| 141 | + boost::intrusive_ptr<DocumentSource> currentMatchCopyDocument = |
| 142 | + prospectiveMatch->clone(prospectiveMatch->getContext()); |
| 143 | + |
| 144 | + auto currentMatchCopyDocumentMatch = |
| 145 | + dynamic_cast<DocumentSourceMatch*>(currentMatchCopyDocument.get()); |
| 146 | + |
| 147 | + paths.renames = std::move(relevantRenames); |
| 148 | + |
| 149 | + // Translate predicate statements based on the projection renames. |
| 150 | + auto matchSplitForProject = currentMatchCopyDocumentMatch->splitMatchByModifiedFields( |
| 151 | + currentMatchCopyDocumentMatch, paths); |
| 152 | + |
| 153 | + if (matchSplitForProject.first) { |
| 154 | + // Perform the swap of the projection and the match stages. |
| 155 | + container->erase(prospectiveMatchItr); |
| 156 | + container->insert(prospectiveProjectionItr, std::move(matchSplitForProject.first)); |
| 157 | + |
| 158 | + if (matchSplitForProject.second) { |
| 159 | + // If there is a portion of the match stage predicate that is conflicting with the |
| 160 | + // projection, re-insert it below the projection stage. |
| 161 | + container->insert(std::next(prospectiveProjectionItr), |
| 162 | + std::move(matchSplitForProject.second)); |
| 163 | + } |
| 164 | + |
| 165 | + return true; |
| 166 | + } |
| 167 | + |
| 168 | + return false; |
| 169 | +} |
| 170 | + |
85 | 171 | boost::intrusive_ptr<DocumentSource> DocumentSourceGroup::createFromBsonWithMaxMemoryUsage(
|
86 | 172 | BSONElement elem,
|
87 | 173 | const boost::intrusive_ptr<ExpressionContext>& expCtx,
|
|
0 commit comments