diff options
author | Alison Lu <alison.lu@mongodb.com> | 2021-07-20 17:51:38 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2021-07-21 13:59:22 +0000 |
commit | 8981461aab4dfe5cc4b0130f90182cbea556fb50 (patch) | |
tree | 378cdcf33ed261d83ca93092b9cab1d178678e26 | |
parent | 58f0b2a63c61656314f1931158fe9d18488673e4 (diff) | |
download | mongo-8981461aab4dfe5cc4b0130f90182cbea556fb50.tar.gz |
SERVER-58617 Allow updates on time-series collections with no metaField
-rw-r--r-- | jstests/core/timeseries/timeseries_update.js | 52 | ||||
-rw-r--r-- | src/mongo/db/commands/write_commands.cpp | 12 | ||||
-rw-r--r-- | src/mongo/db/timeseries/timeseries_update_delete_util.cpp | 20 |
3 files changed, 61 insertions, 23 deletions
diff --git a/jstests/core/timeseries/timeseries_update.js b/jstests/core/timeseries/timeseries_update.js index d5a7cb95280..578b0928b74 100644 --- a/jstests/core/timeseries/timeseries_update.js +++ b/jstests/core/timeseries/timeseries_update.js @@ -32,6 +32,11 @@ const doc2 = { [metaFieldName]: {c: "C", d: 2}, f: [{"k": "K", "v": "V"}], }; +const doc3 = { + _id: 3, + [timeFieldName]: dateTime, + f: "F", +}; TimeseriesTest.run((insert) => { const testDB = db.getSiblingDB(jsTestName()); @@ -46,11 +51,14 @@ TimeseriesTest.run((insert) => { resultDocList, nModified = 0, failCode = null, + hasMetaField = true, ordered = true }) { const coll = testDB.getCollection('t'); - assert.commandWorked(testDB.createCollection( - coll.getName(), {timeseries: {timeField: timeFieldName, metaField: metaFieldName}})); + assert.commandWorked(testDB.createCollection(coll.getName(), { + timeseries: hasMetaField ? {timeField: timeFieldName, metaField: metaFieldName} + : {timeField: timeFieldName}, + })); assert.commandWorked(insert(coll, initialDocList)); const updateCommand = {update: coll.getName(), updates: updateList}; @@ -391,5 +399,45 @@ TimeseriesTest.run((insert) => { resultDocList: [doc2], failCode: ErrorCodes.InvalidOptions, }); + + /*********************** Tests updating a collection with no metaField. **********************/ + // Query on a field which is not the (nonexistent) metaField. + testUpdate({ + initialDocList: [doc3], + updateList: [{ + q: {f: "F"}, + u: {}, + multi: true, + }], + resultDocList: [doc3], + failCode: ErrorCodes.InvalidOptions, + hasMetaField: false, + }); + + // Query on all documents and update them to be empty documents. + testUpdate({ + initialDocList: [doc3], + updateList: [{ + q: {}, + u: {}, + multi: true, + }], + resultDocList: [doc3], + failCode: ErrorCodes.InvalidOptions, + hasMetaField: false, + }); + + // Query on all documents and update them to be nonempty documents. + testUpdate({ + initialDocList: [doc3], + updateList: [{ + q: {}, + u: {f: "FF"}, + multi: true, + }], + resultDocList: [doc3], + failCode: ErrorCodes.InvalidOptions, + hasMetaField: false, + }); }); }()); diff --git a/src/mongo/db/commands/write_commands.cpp b/src/mongo/db/commands/write_commands.cpp index c14430d94e2..1397fe6ce09 100644 --- a/src/mongo/db/commands/write_commands.cpp +++ b/src/mongo/db/commands/write_commands.cpp @@ -1315,14 +1315,7 @@ public: "Time-series buckets collection is missing time-series options", timeseriesOptions); - // TODO: SERVER-58617 Allow updates on time-series collections with no metaField. - uassert( - ErrorCodes::IllegalOperation, - str::stream() - << "Updates on a time-series collection without a metaField are not supported: " - << ns(), - timeseriesOptions->getMetaField() != boost::none); - StringData metaField = *timeseriesOptions->getMetaField(); + StringData metaField = timeseriesOptions->getMetaField().value_or(""); // Create the translated updates to apply, which are used to make a new // UpdateCommandRequest. @@ -1537,8 +1530,7 @@ public: uassert(ErrorCodes::InvalidOptions, "Time-series buckets collection is missing time-series options", timeseriesOptions); - StringData metaField = - timeseriesOptions->getMetaField() ? *timeseriesOptions->getMetaField() : ""; + StringData metaField = timeseriesOptions->getMetaField().value_or(""); std::vector<mongo::write_ops::DeleteOpEntry> timeseriesDeletes; timeseriesDeletes.reserve(request().getDeletes().size()); diff --git a/src/mongo/db/timeseries/timeseries_update_delete_util.cpp b/src/mongo/db/timeseries/timeseries_update_delete_util.cpp index ed5f4520422..5eafea0d762 100644 --- a/src/mongo/db/timeseries/timeseries_update_delete_util.cpp +++ b/src/mongo/db/timeseries/timeseries_update_delete_util.cpp @@ -63,9 +63,7 @@ std::string getRenamedMetaField(StringData field) { * Replaces the first occurrence of the metaField in the given field of the given mutablebson * element with the literal "meta", accounting for uses of the metaField with dot notation. */ -void replaceTimeseriesQueryMetaFieldName(mutablebson::Element elem, - StringData field, - StringData metaField) { +void replaceQueryMetaFieldName(mutablebson::Element elem, StringData field, StringData metaField) { if (isMetaFieldFirstElementOfDottedPathField(field, metaField)) { invariantStatusOK(elem.rename(getRenamedMetaField(field))); } @@ -74,12 +72,12 @@ void replaceTimeseriesQueryMetaFieldName(mutablebson::Element elem, /** * Recurses through the mutablebson element query and replaces any occurrences of the * metaField with "meta" accounting for queries that may be in dot notation. shouldReplaceFieldValue - * is set for $expr queries when "$" + the metaField should be subsitutited for "$meta". + * is set for $expr queries when "$" + the metaField should be substituted for "$meta". */ -void replaceTimeseriesQueryMetaFieldName(mutablebson::Element elem, StringData metaField) { - replaceTimeseriesQueryMetaFieldName(elem, elem.getFieldName(), metaField); +void replaceQueryMetaFieldName(mutablebson::Element elem, StringData metaField) { + replaceQueryMetaFieldName(elem, elem.getFieldName(), metaField); for (size_t i = 0; i < elem.countChildren(); ++i) { - replaceTimeseriesQueryMetaFieldName(elem.findNthChild(i), metaField); + replaceQueryMetaFieldName(elem.findNthChild(i), metaField); } } } // namespace @@ -166,7 +164,7 @@ bool updateOnlyModifiesMetaField(OperationContext* opCtx, BSONObj translateQuery(const BSONObj& query, StringData metaField) { invariant(!metaField.empty()); mutablebson::Document queryDoc(query); - timeseries::replaceTimeseriesQueryMetaFieldName(queryDoc.root(), metaField); + timeseries::replaceQueryMetaFieldName(queryDoc.root(), metaField); return queryDoc.getObject(); } @@ -197,7 +195,7 @@ write_ops::UpdateOpEntry translateUpdate(const BSONObj& translatedQuery, // and replace it if it is the metaField. for (size_t j = 0; j < updatePair.countChildren(); j++) { auto fieldValuePair = updatePair.findNthChild(j); - timeseries::replaceTimeseriesQueryMetaFieldName( + timeseries::replaceQueryMetaFieldName( fieldValuePair, fieldValuePair.getFieldName(), metaField); } } @@ -223,14 +221,14 @@ write_ops::UpdateOpEntry translateUpdate(const BSONObj& translatedQuery, // updatePair = $set: {<newField> : <newExpression>, ...} for (size_t j = 0; j < updatePair.countChildren(); j++) { auto fieldValuePair = updatePair.findNthChild(j); - timeseries::replaceTimeseriesQueryMetaFieldName( + timeseries::replaceQueryMetaFieldName( fieldValuePair, fieldValuePair.getFieldName(), metaField); } } else if (aggOp == "$unset" || aggOp == "$project") { if (updatePair.getType() == BSONType::Array) { // updatePair = $unset: ["field1", "field2", ...] for (size_t j = 0; j < updatePair.countChildren(); j++) { - timeseries::replaceTimeseriesQueryMetaFieldName( + timeseries::replaceQueryMetaFieldName( updatePair, updatePair.findNthChild(j).getValueString(), metaField); |