summaryrefslogtreecommitdiff
path: root/src/mongo/db/bson
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2017-01-24 17:27:28 -0500
committerDavid Storch <david.storch@10gen.com>2017-01-27 10:17:21 -0500
commitc7c8e4151ddc745aea9c0f07ed1890518d00723d (patch)
tree83e7a47f812cd2bd7df5a3bf5242e99202bba8ac /src/mongo/db/bson
parent310ce16e32d0f2c110a0f8e2b11e0e0cbc1617ad (diff)
downloadmongo-c7c8e4151ddc745aea9c0f07ed1890518d00723d.tar.gz
SERVER-5580 track paths containing empty or single-element arrays as multikey
This is required in order for the planner to enforce correct covering behavior.
Diffstat (limited to 'src/mongo/db/bson')
-rw-r--r--src/mongo/db/bson/dotted_path_support.cpp8
-rw-r--r--src/mongo/db/bson/dotted_path_support.h2
-rw-r--r--src/mongo/db/bson/dotted_path_support_test.cpp91
3 files changed, 94 insertions, 7 deletions
diff --git a/src/mongo/db/bson/dotted_path_support.cpp b/src/mongo/db/bson/dotted_path_support.cpp
index 1a9fda88501..63a96686769 100644
--- a/src/mongo/db/bson/dotted_path_support.cpp
+++ b/src/mongo/db/bson/dotted_path_support.cpp
@@ -86,7 +86,6 @@ void _extractAllElementsAlongPath(const BSONObj& obj,
depth + 1,
arrayComponents);
} else {
- size_t nArrElems = 0;
BSONObjIterator i(e.embeddedObject());
while (i.more()) {
BSONElement e2 = i.next();
@@ -97,9 +96,8 @@ void _extractAllElementsAlongPath(const BSONObj& obj,
expandArrayOnTrailingField,
depth + 1,
arrayComponents);
- ++nArrElems;
}
- if (arrayComponents && nArrElems > 1) {
+ if (arrayComponents) {
arrayComponents->insert(depth);
}
}
@@ -109,13 +107,11 @@ void _extractAllElementsAlongPath(const BSONObj& obj,
}
} else {
if (e.type() == Array && expandArrayOnTrailingField) {
- size_t nArrElems = 0;
BSONObjIterator i(e.embeddedObject());
while (i.more()) {
elements.insert(i.next());
- ++nArrElems;
}
- if (arrayComponents && nArrElems > 1) {
+ if (arrayComponents) {
arrayComponents->insert(depth);
}
} else {
diff --git a/src/mongo/db/bson/dotted_path_support.h b/src/mongo/db/bson/dotted_path_support.h
index c9c6676c75a..4d34901338c 100644
--- a/src/mongo/db/bson/dotted_path_support.h
+++ b/src/mongo/db/bson/dotted_path_support.h
@@ -83,7 +83,7 @@ BSONElement extractElementAtPathOrArrayAlongPath(const BSONObj& obj, const char*
* and array elements.
*
* This function fills 'arrayComponents' with the positions (starting at 0) of 'path' corresponding
- * to array values with multiple elements.
+ * to array values.
*
* Some examples:
*
diff --git a/src/mongo/db/bson/dotted_path_support_test.cpp b/src/mongo/db/bson/dotted_path_support_test.cpp
index 06fa6dc2840..341750a9777 100644
--- a/src/mongo/db/bson/dotted_path_support_test.cpp
+++ b/src/mongo/db/bson/dotted_path_support_test.cpp
@@ -194,6 +194,19 @@ TEST(ExtractAllElementsAlongPath, NestedObjectWithEmptyArrayValue) {
obj, "a.b", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
assertBSONElementSetsAreEqual(std::vector<BSONObj>{}, actualElements);
+ assertArrayComponentsAreEqual(std::set<size_t>{1U}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, NestedObjectWithEmptyArrayValueAndExpandParamIsFalse) {
+ BSONObj obj(fromjson("{a: {b: []}}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = false;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << BSONArray())}, actualElements);
assertArrayComponentsAreEqual(std::set<size_t>{}, actualArrayComponents);
}
@@ -207,6 +220,19 @@ TEST(ExtractAllElementsAlongPath, NestedObjectWithSingletonArrayValue) {
obj, "a.b", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
assertBSONElementSetsAreEqual({BSON("" << 1)}, actualElements);
+ assertArrayComponentsAreEqual(std::set<size_t>{1U}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, NestedObjectWithSingletonArrayValueAndExpandParamIsFalse) {
+ BSONObj obj(fromjson("{a: {b: {c: [3]}}}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = false;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b.c", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << BSON_ARRAY(3))}, actualElements);
assertArrayComponentsAreEqual(std::set<size_t>{}, actualArrayComponents);
}
@@ -479,5 +505,70 @@ TEST(ExtractAllElementsAlongPath, DoesExpandArrayFoundAfterPositionalSpecificati
assertArrayComponentsAreEqual({1U}, actualArrayComponents);
}
+TEST(ExtractAllElementsAlongPath, PositionalElementsNotConsideredArrayComponents) {
+ BSONObj obj(fromjson("{a: [{b: [1, 2]}]}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = true;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.0.b.1", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << 2)}, actualElements);
+ assertArrayComponentsAreEqual(std::set<size_t>{}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, TrailingArrayIsExpandedEvenIfPositional) {
+ BSONObj obj(fromjson("{a: {b: [0, [1, 2]]}}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = true;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b.1", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << 1), BSON("" << 2)}, actualElements);
+ assertArrayComponentsAreEqual({2U}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, PositionalTrailingArrayNotExpandedIfExpandParameterIsFalse) {
+ BSONObj obj(fromjson("{a: {b: [0, [1, 2]]}}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = false;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b.1", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << BSON_ARRAY(1 << 2))}, actualElements);
+ assertArrayComponentsAreEqual(std::set<size_t>{}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, MidPathEmptyArrayIsConsideredAnArrayComponent) {
+ BSONObj obj(fromjson("{a: [{b: []}]}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = true;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b.c", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual(std::vector<BSONObj>{}, actualElements);
+ assertArrayComponentsAreEqual({0U, 1U}, actualArrayComponents);
+}
+
+TEST(ExtractAllElementsAlongPath, MidPathSingletonArrayIsConsideredAnArrayComponent) {
+ BSONObj obj(fromjson("{a: {b: [{c: 3}]}}"));
+
+ BSONElementSet actualElements;
+ const bool expandArrayOnTrailingField = true;
+ std::set<size_t> actualArrayComponents;
+ dps::extractAllElementsAlongPath(
+ obj, "a.b.c", actualElements, expandArrayOnTrailingField, &actualArrayComponents);
+
+ assertBSONElementSetsAreEqual({BSON("" << 3)}, actualElements);
+ assertArrayComponentsAreEqual({1U}, actualArrayComponents);
+}
+
} // namespace
} // namespace mongo