diff --git a/jstests/noPassthrough/deprecated_distinct.js b/jstests/noPassthrough/deprecated_distinct.js new file mode 100644 index 0000000000..6645f79f50 --- /dev/null +++ b/jstests/noPassthrough/deprecated_distinct.js @@ -0,0 +1,48 @@ +// The distinct command is deprecated in 5.0. +// +// In this test, we run the distinct command several times. +// We want to make sure that the deprecation warning message is only logged once despite +// the multiple invocations in an effort to not clutter the dev's console. +// More specifically, we expect to only log 1/127 of distinct() events. + +(function() { +"use strict"; +load("jstests/libs/log.js"); // For findMatchingLogLine, findMatchingLogLines + +jsTest.log('Test standalone'); +const standalone = MongoRunner.runMongod({}); +const dbName = 'test'; +const collName = "test_distinct_command_deprecation_messaging"; +const db = standalone.getDB(dbName); +const coll = db.getCollection(collName); + +coll.drop(); +assert.commandWorked(coll.insert({a: 1, b: 2})); +assert.commandWorked(coll.insert({a: 2, b: 2})); +assert.commandWorked(coll.insert({a: 2, b: 1})); +assert.commandWorked(coll.insert({a: 2, b: 2})); +assert.commandWorked(coll.insert({a: 3, b: 2})); +assert.commandWorked(coll.insert({a: 4, b: 1})); +assert.commandWorked(coll.insert({a: 4, b: 1})); + +// Test running the distinct command directly, rather than via shell helper. +let res = assert.commandWorked(db.runCommand({distinct: collName, key: "a"})); +assert.eq([1, 2, 3, 4], res.values.sort()); + +res = assert.commandWorked(db.runCommand({distinct: collName, key: "a", query: null})); +assert.eq([1, 2, 3, 4], res.values.sort()); + +res = assert.commandWorked(db.runCommand({distinct: collName, key: "a", query: {b: 2}})); +assert.eq([1, 2, 3], res.values.sort()); + +assert.commandFailed(db.runCommand({distinct: collName, key: "a", query: 1})); + +const globalLogs = db.adminCommand({getLog: 'global'}); +const fieldMatcher = { + msg: + "The distinct command is deprecated. For more information, see https://docs.mongodb.com/manual/reference/method/db.collection.distinct/" +}; +const matchingLogLines = [...findMatchingLogLines(globalLogs.log, fieldMatcher)]; +assert.eq(matchingLogLines.length, 1, matchingLogLines); +MongoRunner.stopMongod(standalone); +})(); \ No newline at end of file diff --git a/src/mongo/db/query/parsed_distinct.cpp b/src/mongo/db/query/parsed_distinct.cpp index 59c15f39f7..c7bf985d6c 100644 --- a/src/mongo/db/query/parsed_distinct.cpp +++ b/src/mongo/db/query/parsed_distinct.cpp @@ -26,6 +26,7 @@ * exception statement from all source files in the program, then also delete * it in the license file. */ +#define MONGO_LOGV2_DEFAULT_COMPONENT ::mongo::logv2::LogComponent::kCommand #include "mongo/platform/basic.h" @@ -40,6 +41,8 @@ #include "mongo/db/query/query_request_helper.h" #include "mongo/db/repl/read_concern_args.h" #include "mongo/idl/idl_parser.h" +#include "mongo/logv2/log.h" +#include "mongo/util/debug_util.h" #include "mongo/util/str.h" namespace mongo { @@ -49,7 +52,8 @@ const char ParsedDistinct::kQueryField[] = "query"; const char ParsedDistinct::kCollationField[] = "collation"; namespace { - +// Used to log occasional deprecation warnings when this command is invoked. +Rarely _sampler; /** * Helper for when converting a distinct() to an aggregation pipeline. This function will add * $unwind stages for each subpath of 'path'. @@ -255,6 +259,11 @@ StatusWith ParsedDistinct::parse(OperationContext* opCtx, const ExtensionsCallback& extensionsCallback, bool isExplain, const CollatorInterface* defaultCollator) { + if (_sampler.tick()) { + LOGV2_WARNING(5725701, + "The distinct command is deprecated. For more information, see " + "https://docs.mongodb.com/manual/reference/method/db.collection.distinct/"); + } IDLParserErrorContext ctx("distinct"); DistinctCommandRequest parsedDistinct(nss); @@ -332,4 +341,5 @@ StatusWith ParsedDistinct::parse(OperationContext* opCtx, return ParsedDistinct(std::move(cq.getValue()), parsedDistinct.getKey().toString()); } + } // namespace mongo