mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
SERVER-31696 Rename path prefixes in applyRenamesToExpression().
Previously, applyRenamesToExpression() would only rename a path if the entire path matched the rename rule.
This commit is contained in:
parent
29769e9514
commit
d12505f554
@ -172,4 +172,30 @@
|
||||
ixscan = getAggPlanStage(explain, "IXSCAN");
|
||||
assert.neq(null, ixscan, tojson(explain));
|
||||
assert.eq({"a.b.c": 1}, ixscan.keyPattern, tojson(ixscan));
|
||||
|
||||
// Test that we correctly match on the subfield of a renamed field. Here, a match on "x.b.c"
|
||||
// follows an "a" to "x" rename. When we move the match stage in front of the rename, the match
|
||||
// should also get rewritten to use "a.b.c" as its filter.
|
||||
pipeline = [{$project: {x: "$a"}}, {$match: {"x.b.c": 1}}];
|
||||
assert.eq([{_id: 0, x: [{b: [{c: 1}, {c: 2}]}, {b: [{c: 3}, {c: 4}]}]}],
|
||||
coll.aggregate(pipeline).toArray());
|
||||
explain = coll.explain().aggregate(pipeline);
|
||||
ixscan = getAggPlanStage(explain, "IXSCAN");
|
||||
assert.neq(null, ixscan, tojson(explain));
|
||||
assert.eq({"a.b.c": 1}, ixscan.keyPattern, tojson(ixscan));
|
||||
|
||||
// Test that we correctly match on the subfield of a renamed field when the rename results from
|
||||
// a $map operation. Here, a match on "d.e.c" follows an "a.b" to "d.e" rename. When we move the
|
||||
// match stage in front of the renaming $map operation, the match should also get rewritten to
|
||||
// use "a.b.c" as its filter.
|
||||
pipeline = [
|
||||
{$project: {d: {$map: {input: "$a", as: "iter", in : {e: "$$iter.b"}}}}},
|
||||
{$match: {"d.e.c": 7}}
|
||||
];
|
||||
assert.eq([{_id: 1, d: [{e: [{c: 5}, {c: 6}]}, {e: [{c: 7}, {c: 8}]}]}],
|
||||
coll.aggregate(pipeline).toArray());
|
||||
explain = coll.explain().aggregate(pipeline);
|
||||
ixscan = getAggPlanStage(explain, "IXSCAN");
|
||||
assert.neq(null, ixscan, tojson(explain));
|
||||
assert.eq({"a.b.c": 1}, ixscan.keyPattern, tojson(ixscan));
|
||||
}());
|
||||
|
@ -283,11 +283,8 @@ void applyRenamesToExpression(MatchExpression* expr, const StringMap<std::string
|
||||
}
|
||||
|
||||
if (expr->getCategory() == MatchExpression::MatchCategory::kLeaf) {
|
||||
auto it = renames.find(expr->path());
|
||||
if (it != renames.end()) {
|
||||
LeafMatchExpression* leafExpr = checked_cast<LeafMatchExpression*>(expr);
|
||||
leafExpr->setPath(it->second).transitional_ignore();
|
||||
}
|
||||
LeafMatchExpression* leafExpr = checked_cast<LeafMatchExpression*>(expr);
|
||||
leafExpr->applyRename(renames);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < expr->numChildren(); ++i) {
|
||||
|
@ -85,6 +85,43 @@ public:
|
||||
return Status::OK();
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds an applicable rename from 'renameList' (if one exists) and applies it to the expression
|
||||
* path. Each pair in 'renameList' specifies a path prefix that should be renamed (as the first
|
||||
* element) and the path components that should replace the renamed prefix (as the second
|
||||
* element).
|
||||
*/
|
||||
void applyRename(const StringMap<std::string>& renameList) {
|
||||
FieldRef pathFieldRef(_path);
|
||||
|
||||
int renamesFound = 0;
|
||||
for (auto rename : renameList) {
|
||||
if (rename.first == _path) {
|
||||
_rewrittenPath = rename.second;
|
||||
invariantOK(setPath(_rewrittenPath));
|
||||
|
||||
++renamesFound;
|
||||
}
|
||||
|
||||
FieldRef prefixToRename(rename.first);
|
||||
if (prefixToRename.isPrefixOf(pathFieldRef)) {
|
||||
// Get the 'pathTail' by chopping off the 'prefixToRename' path components from the
|
||||
// beginning of the 'pathFieldRef' path.
|
||||
auto pathTail = pathFieldRef.dottedSubstring(prefixToRename.numParts(),
|
||||
pathFieldRef.numParts());
|
||||
// Replace the chopped off components with the component names resulting from the
|
||||
// rename.
|
||||
_rewrittenPath = str::stream() << rename.second << "." << pathTail.toString();
|
||||
invariantOK(setPath(_rewrittenPath));
|
||||
|
||||
++renamesFound;
|
||||
}
|
||||
}
|
||||
|
||||
// There should never be multiple applicable renames.
|
||||
invariant(renamesFound <= 1);
|
||||
}
|
||||
|
||||
protected:
|
||||
void _doAddDependencies(DepsTracker* deps) const final {
|
||||
if (!_path.empty()) {
|
||||
@ -95,5 +132,9 @@ protected:
|
||||
private:
|
||||
StringData _path;
|
||||
ElementPath _elementPath;
|
||||
|
||||
// We use this when we rewrite the value in '_path' and we need a backing store for the
|
||||
// rewritten string.
|
||||
std::string _rewrittenPath;
|
||||
};
|
||||
} // namespace mongo
|
||||
|
Loading…
Reference in New Issue
Block a user