summaryrefslogtreecommitdiff
path: root/src/mongo/db/pipeline/expression.cpp
diff options
context:
space:
mode:
authorBenjamin Murphy <benjamin_murphy@me.com>2016-04-12 13:20:55 -0400
committerBenjamin Murphy <benjamin_murphy@me.com>2016-04-26 11:28:01 -0400
commit5c3e0d4855415cbab4bd75732208f832c11f4889 (patch)
tree911396b289d2ed81f298bef25517943fb0ee30ea /src/mongo/db/pipeline/expression.cpp
parent5751b5417080e4f10f25ade1a6b6f58efc263fbb (diff)
downloadmongo-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.cpp66
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 {