diff options
author | Kyle Suarez <kyle.suarez@mongodb.com> | 2017-09-20 14:31:17 -0400 |
---|---|---|
committer | Kyle Suarez <kyle.suarez@mongodb.com> | 2017-09-20 14:31:17 -0400 |
commit | 7a15db88968b9f6dd4418f4a89a2826c82b2ecac (patch) | |
tree | 7ee7b58ac2ace0609561c3c1467c0dded2753a5e | |
parent | 77bbdee3f8b59b1e070129616360f87e190a540b (diff) | |
download | mongo-7a15db88968b9f6dd4418f4a89a2826c82b2ecac.tar.gz |
SERVER-30695 uniqueItems must ignore field order when comparing documents
3 files changed, 16 insertions, 7 deletions
diff --git a/jstests/core/json_schema/unique_items.js b/jstests/core/json_schema/unique_items.js index f94fb5546d8..08c8ae84211 100644 --- a/jstests/core/json_schema/unique_items.js +++ b/jstests/core/json_schema/unique_items.js @@ -41,10 +41,8 @@ assertSchemaMatch(coll, schema, {a: [{a: 1}, {a: 1}]}, false); assertSchemaMatch(coll, schema, {a: [[1, 2], [1, 2]]}, false); assertSchemaMatch(coll, schema, {a: [null, null]}, false); - - // TODO (SERVER-30695): uniqueItems should compare objects in a field order-insensitive way when - // testing for uniqueness. - assertSchemaMatch(coll, schema, {a: [{x: 1, y: 1}, {y: 1, x: 1}]}, true); + assertSchemaMatch(coll, schema, {a: [{x: 1, y: 1}, {y: 1, x: 1}]}, false); + assertSchemaMatch(coll, schema, {a: [{x: [1, 2], y: "a"}, {y: "a", x: [1, 2]}]}, false); // Test that {uniqueItems: false} has no effect. schema = {properties: {a: {uniqueItems: false}}}; @@ -60,4 +58,6 @@ assertSchemaMatch(coll, schema, {a: [{a: 1}, {a: 1}]}, true); assertSchemaMatch(coll, schema, {a: [[1, 2], [1, 2]]}, true); assertSchemaMatch(coll, schema, {a: [null, null]}, true); + assertSchemaMatch(coll, schema, {a: [{x: 1, y: 1}, {y: 1, x: 1}]}, true); + assertSchemaMatch(coll, schema, {a: [{x: [1, 2], y: "a"}, {y: "a", x: [1, 2]}]}, true); }()); diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h index 570cf448f07..07beff92319 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h +++ b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items.h @@ -30,13 +30,16 @@ #include <utility> -#include "mongo/bson/bsonelement_comparator.h" +#include "mongo/bson/unordered_fields_bsonelement_comparator.h" #include "mongo/db/matcher/expression_array.h" namespace mongo { /** - * Matches arrays whose elements are all unique. + * Matches arrays whose elements are all unique. When comparing elements, + * + * - strings are always compared using the "simple" string comparator; and + * - objects are compared in a field order-independent manner. */ class InternalSchemaUniqueItemsMatchExpression final : public ArrayMatchingMatchExpression { public: @@ -81,6 +84,6 @@ public: private: // The comparator to use when comparing BSONElements, which will never use a collation. - BSONElementComparator _comparator{BSONElementComparator::FieldNamesMode::kIgnore, nullptr}; + UnorderedFieldsBSONElementComparator _comparator; }; } // namespace mongo diff --git a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp index 16628681ae1..5e9d1a119b4 100644 --- a/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp +++ b/src/mongo/db/matcher/schema/expression_internal_schema_unique_items_test.cpp @@ -64,6 +64,7 @@ TEST(InternalSchemaUniqueItemsMatchExpression, MatchesArrayOfUniqueItems) { ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: [1, 'bar', {}, [], null]}"))); ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: [{x: 1}, {x: 2}, {x: 2, y: 3}]}"))); ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: [[1], [1, 2], 1]}"))); + ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: [['a', 'b'], ['b', 'a']]}"))); } TEST(InternalSchemaUniqueItemsMatchExpression, MatchesNestedArrayOfUniqueItems) { @@ -72,6 +73,7 @@ TEST(InternalSchemaUniqueItemsMatchExpression, MatchesNestedArrayOfUniqueItems) ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [1, 'bar', {}, [], null]}}"))); ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [{x: 1}, {x: 2}, {x: 2, y: 3}]}}"))); ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [[1], [1, 2], 1]}}"))); + ASSERT_TRUE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [['a', 'b'], ['b', 'a']]}}"))); } TEST(InternalSchemaUniqueItemsMatchExpression, RejectsArrayWithDuplicates) { @@ -79,6 +81,8 @@ TEST(InternalSchemaUniqueItemsMatchExpression, RejectsArrayWithDuplicates) { ASSERT_OK(uniqueItems.init("foo")); ASSERT_FALSE(uniqueItems.matchesBSON(fromjson("{foo: [1, 1, 1]}"))); ASSERT_FALSE(uniqueItems.matchesBSON(fromjson("{foo: [['bar'], ['bar']]}"))); + ASSERT_FALSE( + uniqueItems.matchesBSON(fromjson("{foo: [{x: 'a', y: [1, 2]}, {y: [1, 2], x: 'a'}]}"))); } TEST(InternalSchemaUniqueItemsMatchExpression, RejectsNestedArrayWithDuplicates) { @@ -86,6 +90,8 @@ TEST(InternalSchemaUniqueItemsMatchExpression, RejectsNestedArrayWithDuplicates) ASSERT_OK(uniqueItems.init("foo")); ASSERT_FALSE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [1, 1, 1]}}"))); ASSERT_FALSE(uniqueItems.matchesBSON(fromjson("{foo: {bar: [['baz'], ['baz']]}}"))); + ASSERT_FALSE(uniqueItems.matchesBSON( + fromjson("{foo: {bar: [{x: 'a', y: [1, 2]}, {y: [1, 2], x: 'a'}]}}"))); } TEST(InternalSchemaUniqueItemsMatchExpression, FieldNameSignificantWhenComparingNestedObjects) { |