183 lines
7.2 KiB
JavaScript
183 lines
7.2 KiB
JavaScript
/**
|
|
* Test the behavior of field names containing special characters, including:
|
|
* - dots
|
|
* - $-prefixed
|
|
* - reserved $-prefixed ($ref, $id, $db)
|
|
* - regex
|
|
*
|
|
* contained in a top-level element, embedded element, and within _id.
|
|
*
|
|
* @tags: [assumes_unsharded_collection]
|
|
*/
|
|
(function() {
|
|
"use strict";
|
|
|
|
const coll = db.field_name_validation;
|
|
coll.drop();
|
|
|
|
//
|
|
// Insert command field name validation.
|
|
//
|
|
|
|
// Test that dotted field names are allowed.
|
|
assert.writeOK(coll.insert({"a.b": 1}));
|
|
assert.writeOK(coll.insert({"_id.a": 1}));
|
|
assert.writeOK(coll.insert({a: {"a.b": 1}}));
|
|
assert.writeOK(coll.insert({_id: {"a.b": 1}}));
|
|
|
|
// Test that _id cannot be a regex.
|
|
assert.writeError(coll.insert({_id: /a/}));
|
|
|
|
// Test that _id cannot be an array.
|
|
assert.writeError(coll.insert({_id: [9]}));
|
|
|
|
// Test that $-prefixed field names are allowed in embedded objects.
|
|
assert.writeOK(coll.insert({a: {$b: 1}}));
|
|
assert.eq(1, coll.find({"a.$b": 1}).itcount());
|
|
|
|
// Test that $-prefixed field names are not allowed at the top level.
|
|
assert.writeErrorWithCode(coll.insert({$a: 1}), ErrorCodes.BadValue);
|
|
assert.writeErrorWithCode(coll.insert({valid: 1, $a: 1}), ErrorCodes.BadValue);
|
|
|
|
// Test that reserved $-prefixed field names are also not allowed.
|
|
assert.writeErrorWithCode(coll.insert({$ref: 1}), ErrorCodes.BadValue);
|
|
assert.writeErrorWithCode(coll.insert({$id: 1}), ErrorCodes.BadValue);
|
|
assert.writeErrorWithCode(coll.insert({$db: 1}), ErrorCodes.BadValue);
|
|
|
|
// Test that _id cannot be an object with an element that has a $-prefixed field name.
|
|
assert.writeErrorWithCode(coll.insert({_id: {$b: 1}}), ErrorCodes.DollarPrefixedFieldName);
|
|
assert.writeErrorWithCode(coll.insert({_id: {a: 1, $b: 1}}),
|
|
ErrorCodes.DollarPrefixedFieldName);
|
|
|
|
// Should not enforce the same restrictions on an embedded _id field.
|
|
assert.writeOK(coll.insert({a: {_id: [9]}}));
|
|
assert.writeOK(coll.insert({a: {_id: /a/}}));
|
|
assert.writeOK(coll.insert({a: {_id: {$b: 1}}}));
|
|
|
|
//
|
|
// Update command field name validation.
|
|
//
|
|
coll.drop();
|
|
|
|
// Dotted fields are allowed in an update.
|
|
assert.writeOK(coll.update({}, {"a.b": 1}, {upsert: true}));
|
|
assert.eq(0, coll.find({"a.b": 1}).itcount());
|
|
assert.eq(1, coll.find({}).itcount());
|
|
|
|
// Dotted fields represent paths in $set.
|
|
assert.writeOK(coll.update({}, {$set: {"a.b": 1}}, {upsert: true}));
|
|
assert.eq(1, coll.find({"a.b": 1}).itcount());
|
|
|
|
// Dotted fields represent paths in the query object.
|
|
assert.writeOK(coll.update({"a.b": 1}, {$set: {"a.b": 2}}));
|
|
assert.eq(1, coll.find({"a.b": 2}).itcount());
|
|
assert.eq(1, coll.find({a: {b: 2}}).itcount());
|
|
|
|
assert.writeOK(coll.update({"a.b": 2}, {"a.b": 3}));
|
|
assert.eq(0, coll.find({"a.b": 3}).itcount());
|
|
|
|
// $-prefixed field names are not allowed.
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$c: 1}, {upsert: true}),
|
|
ErrorCodes.FailedToParse);
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$set: {$c: 1}}, {upsert: true}),
|
|
ErrorCodes.DollarPrefixedFieldName);
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$set: {c: {$d: 1}}}, {upsert: true}),
|
|
ErrorCodes.DollarPrefixedFieldName);
|
|
|
|
// Reserved $-prefixed field names are also not allowed.
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$ref: 1}), ErrorCodes.FailedToParse);
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$id: 1}), ErrorCodes.FailedToParse);
|
|
assert.writeErrorWithCode(coll.update({"a.b": 1}, {$db: 1}), ErrorCodes.FailedToParse);
|
|
|
|
//
|
|
// FindAndModify field name validation.
|
|
//
|
|
coll.drop();
|
|
|
|
// Dotted fields are allowed in update object.
|
|
coll.findAndModify({query: {_id: 0}, update: {_id: 0, "a.b": 1}, upsert: true});
|
|
assert.eq([{_id: 0, "a.b": 1}], coll.find({_id: 0}).toArray());
|
|
|
|
// Dotted fields represent paths in $set.
|
|
coll.findAndModify({query: {_id: 1}, update: {$set: {_id: 1, "a.b": 1}}, upsert: true});
|
|
assert.eq([{_id: 1, a: {b: 1}}], coll.find({_id: 1}).toArray());
|
|
|
|
// Dotted fields represent paths in the query object.
|
|
coll.findAndModify({query: {_id: 0, "a.b": 1}, update: {"a.b": 2}});
|
|
assert.eq([{_id: 0, "a.b": 1}], coll.find({_id: 0}).toArray());
|
|
|
|
coll.findAndModify({query: {_id: 1, "a.b": 1}, update: {$set: {_id: 1, "a.b": 2}}});
|
|
assert.eq([{_id: 1, a: {b: 2}}], coll.find({_id: 1}).toArray());
|
|
|
|
// $-prefixed field names are not allowed.
|
|
assert.throws(function() {
|
|
coll.findAndModify({query: {_id: 1}, update: {_id: 1, $invalid: 1}});
|
|
});
|
|
assert.throws(function() {
|
|
coll.findAndModify({query: {_id: 1}, update: {$set: {_id: 1, $invalid: 1}}});
|
|
});
|
|
|
|
// Reserved $-prefixed field names are also not allowed.
|
|
assert.throws(function() {
|
|
coll.findAndModify({query: {_id: 1}, update: {_id: 1, $ref: 1}});
|
|
});
|
|
assert.throws(function() {
|
|
coll.findAndModify({query: {_id: 1}, update: {_id: 1, $id: 1}});
|
|
});
|
|
assert.throws(function() {
|
|
coll.findAndModify({query: {_id: 1}, update: {_id: 1, $db: 1}});
|
|
});
|
|
|
|
//
|
|
// Aggregation field name validation.
|
|
//
|
|
coll.drop();
|
|
|
|
assert.writeOK(coll.insert({_id: {a: 1, b: 2}, "c.d": 3}));
|
|
|
|
// Dotted fields represent paths in an aggregation pipeline.
|
|
assert.eq(coll.aggregate([{$match: {"_id.a": 1}}, {$project: {"_id.b": 1}}]).toArray(),
|
|
[{_id: {b: 2}}]);
|
|
assert.eq(coll.aggregate([{$match: {"c.d": 3}}, {$project: {"_id.b": 1}}]).toArray(), []);
|
|
|
|
assert.eq(coll.aggregate([{$project: {"_id.a": 1}}]).toArray(), [{_id: {a: 1}}]);
|
|
assert.eq(coll.aggregate([{$project: {"c.d": 1, _id: 0}}]).toArray(), [{}]);
|
|
|
|
assert.eq(coll.aggregate([
|
|
{$addFields: {"new.field": {$multiply: ["$c.d", "$_id.a"]}}},
|
|
{$project: {"new.field": 1, _id: 0}}
|
|
])
|
|
.toArray(),
|
|
[{new: {field: null}}]);
|
|
|
|
assert.eq(coll.aggregate([{$group: {_id: "$_id.a", e: {$sum: "$_id.b"}}}]).toArray(),
|
|
[{_id: 1, e: 2}]);
|
|
assert.eq(coll.aggregate([{$group: {_id: "$_id.a", e: {$sum: "$c.d"}}}]).toArray(),
|
|
[{_id: 1, e: 0}]);
|
|
|
|
// Accumulation statements cannot have a dotted field name.
|
|
assert.commandFailed(db.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [{$group: {_id: "$_id.a", "e.f": {$sum: "$_id.b"}}}]
|
|
}));
|
|
|
|
// $-prefixed field names are not allowed in an aggregation pipeline.
|
|
assert.commandFailed(
|
|
db.runCommand({aggregate: coll.getName(), pipeline: [{$match: {"$invalid": 1}}]}));
|
|
|
|
assert.commandFailed(db.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [{$project: {"_id.a": 1, "$newField": {$multiply: ["$_id.b", "$_id.a"]}}}]
|
|
}));
|
|
|
|
assert.commandFailed(db.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [{$addFields: {"_id.a": 1, "$newField": {$multiply: ["$_id.b", "$_id.a"]}}}]
|
|
}));
|
|
|
|
assert.commandFailed(db.runCommand({
|
|
aggregate: coll.getName(),
|
|
pipeline: [{$group: {_id: "$_id.a", "$invalid": {$sum: "$_id.b"}}}]
|
|
}));
|
|
})();
|