diff options
author | Benjamin Murphy <benjamin_murphy@me.com> | 2016-04-12 13:20:55 -0400 |
---|---|---|
committer | Benjamin Murphy <benjamin_murphy@me.com> | 2016-04-26 11:28:01 -0400 |
commit | 5c3e0d4855415cbab4bd75732208f832c11f4889 (patch) | |
tree | 911396b289d2ed81f298bef25517943fb0ee30ea /src/mongo/db/pipeline/expression.cpp | |
parent | 5751b5417080e4f10f25ade1a6b6f58efc263fbb (diff) | |
download | mongo-5c3e0d4855415cbab4bd75732208f832c11f4889.tar.gz |
SERVER-6773 Aggregation now supports the split expression.
Diffstat (limited to 'src/mongo/db/pipeline/expression.cpp')
-rw-r--r-- | src/mongo/db/pipeline/expression.cpp | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/mongo/db/pipeline/expression.cpp b/src/mongo/db/pipeline/expression.cpp index 465c98aa450..f462052d856 100644 --- a/src/mongo/db/pipeline/expression.cpp +++ b/src/mongo/db/pipeline/expression.cpp @@ -3069,6 +3069,72 @@ const char* ExpressionSize::getOpName() const { return "$size"; } +/* ----------------------- ExpressionSplit --------------------------- */ + +namespace { + +bool stringHasTokenAtIndex(size_t index, const std::string& input, const std::string& token) { + if (token.size() + index > input.size()) { + return false; + } + + return input.compare(index, token.size(), token) == 0; +} + +} // namespace + +Value ExpressionSplit::evaluateInternal(Variables* vars) const { + Value inputArg = vpOperand[0]->evaluateInternal(vars); + Value separatorArg = vpOperand[1]->evaluateInternal(vars); + + if (inputArg.nullish() || separatorArg.nullish()) { + return Value(BSONNULL); + } + + uassert(40085, + str::stream() << "$split requires an expression that evaluates to a string as a first " + "argument, found: " << typeName(inputArg.getType()), + inputArg.getType() == BSONType::String); + uassert(40086, + str::stream() << "$split requires an expression that evaluates to a string as a second " + "argument, found: " << typeName(separatorArg.getType()), + separatorArg.getType() == BSONType::String); + + std::string input = inputArg.getString(); + std::string separator = separatorArg.getString(); + + uassert(40087, "$split requires a non-empty separator", !separator.empty()); + + std::vector<Value> output; + + // Keep track of the index at which the current output string began. + size_t splitStartIndex = 0; + + // Iterate through 'input' and check to see if 'separator' matches at any point. + for (size_t i = 0; i < input.size();) { + if (stringHasTokenAtIndex(i, input, separator)) { + // We matched; add the current string to our output and jump ahead. + StringData splitString(input.c_str() + splitStartIndex, i - splitStartIndex); + output.push_back(Value(splitString)); + i += separator.size(); + splitStartIndex = i; + } else { + // We did not match, continue to the next character. + ++i; + } + } + + StringData splitString(input.c_str() + splitStartIndex, input.size() - splitStartIndex); + output.push_back(Value(splitString)); + + return Value(output); +} + +REGISTER_EXPRESSION(split, ExpressionSplit::parse); +const char* ExpressionSplit::getOpName() const { + return "$split"; +} + /* ----------------------- ExpressionSqrt ---------------------------- */ Value ExpressionSqrt::evaluateNumericArg(const Value& numericArg) const { |