summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTed Tuckman <ted.tuckman@mongodb.com>2020-02-27 14:44:11 -0500
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-28 17:57:51 +0000
commit314d315015c1c25ed23c470aaa2c4b2a59382b5a (patch)
tree6bff58f639ddb28a1404c3a99d4ed459ca21266e
parentd656e185f2ca18f3963581c5bd0279ca69c256f9 (diff)
downloadmongo-314d315015c1c25ed23c470aaa2c4b2a59382b5a.tar.gz
SERVER-46110 Expose $out functionality
-rw-r--r--jstests/aggregation/explain_writing_aggs.js3
-rw-r--r--jstests/aggregation/sources/out/replace_collection.js11
-rw-r--r--jstests/auth/lib/commands_lib.js2
-rw-r--r--jstests/libs/override_methods/implicitly_wrap_pipelines_in_facets.js1
-rw-r--r--src/mongo/db/commands/mr_common.cpp2
-rw-r--r--src/mongo/db/pipeline/document_source_out.cpp70
-rw-r--r--src/mongo/db/pipeline/document_source_out.h32
-rw-r--r--src/mongo/db/pipeline/document_source_out_test.cpp10
-rw-r--r--src/mongo/db/pipeline/pipeline_test.cpp2
9 files changed, 39 insertions, 94 deletions
diff --git a/jstests/aggregation/explain_writing_aggs.js b/jstests/aggregation/explain_writing_aggs.js
index 077119daa3f..a6d2a937670 100644
--- a/jstests/aggregation/explain_writing_aggs.js
+++ b/jstests/aggregation/explain_writing_aggs.js
@@ -38,7 +38,8 @@ let explain = sourceColl.explain("queryPlanner").aggregate([{$out: targetColl.ge
let outExplain = getAggPlanStage(explain, "$out");
assert.neq(outExplain, null, explain);
-assert.eq(outExplain.$out, targetColl.getName(), explain);
+assert.eq(outExplain.$out.coll, targetColl.getName(), explain);
+assert.eq(outExplain.$out.db, db.getName(), explain);
assert.eq(targetColl.find().itcount(), 0, explain);
// Verify that execution explains don't error for $out.
diff --git a/jstests/aggregation/sources/out/replace_collection.js b/jstests/aggregation/sources/out/replace_collection.js
index 1544c398822..81a83bbdb4f 100644
--- a/jstests/aggregation/sources/out/replace_collection.js
+++ b/jstests/aggregation/sources/out/replace_collection.js
@@ -26,7 +26,7 @@ assert.commandWorked(coll.insert({_id: 0}));
coll.aggregate(pipeline);
assert.eq(1, targetColl.find().itcount());
-// Test $internalOutToDifferentDB with a non-existent database. This is only expected to work in a
+// Test $out with a non-existent database. This is only expected to work in a
// non-sharded environment.
const destDB = db.getSiblingDB("outDifferentDB");
destDB.dropDatabase();
@@ -34,16 +34,11 @@ if (FixtureHelpers.isMongos(db)) {
assert.commandFailedWithCode(db.runCommand({
aggregate: coll.getName(),
cursor: {},
- pipeline: [{
- $internalOutToDifferentDB:
- {db: destDB.getName(), coll: destDB.outDifferentColl.getName()}
- }]
+ pipeline: [{$out: {db: destDB.getName(), coll: destDB.outDifferentColl.getName()}}]
}),
ErrorCodes.NamespaceNotFound);
} else {
- coll.aggregate({
- $internalOutToDifferentDB: {db: destDB.getName(), coll: destDB.outDifferentColl.getName()}
- });
+ coll.aggregate({$out: {db: destDB.getName(), coll: destDB.outDifferentColl.getName()}});
assert.eq(1, destDB.outDifferentColl.find().itcount());
}
diff --git a/jstests/auth/lib/commands_lib.js b/jstests/auth/lib/commands_lib.js
index 41f1cc3489c..646b025aa1d 100644
--- a/jstests/auth/lib/commands_lib.js
+++ b/jstests/auth/lib/commands_lib.js
@@ -1111,7 +1111,7 @@ var authCommandsLib = {
command: function(state, args) {
return {
aggregate: "foo",
- pipeline: [{$out: "foo_out"}],
+ pipeline: [{$out: {db: "foo", coll: "foo_out"}}],
cursor: {},
bypassDocumentValidation: args.bypassDocumentValidation,
};
diff --git a/jstests/libs/override_methods/implicitly_wrap_pipelines_in_facets.js b/jstests/libs/override_methods/implicitly_wrap_pipelines_in_facets.js
index ab680de1521..92199015faf 100644
--- a/jstests/libs/override_methods/implicitly_wrap_pipelines_in_facets.js
+++ b/jstests/libs/override_methods/implicitly_wrap_pipelines_in_facets.js
@@ -32,7 +32,6 @@ Mongo.prototype.runCommand = function(dbName, cmdObj, options) {
'$indexStats',
'$merge',
'$out',
- '$internalOutToDifferentDB'
];
for (let stageSpec of originalPipeline) {
// Skip wrapping the pipeline in a $facet stage if it has an invalid stage
diff --git a/src/mongo/db/commands/mr_common.cpp b/src/mongo/db/commands/mr_common.cpp
index 7343a63ac89..26540980227 100644
--- a/src/mongo/db/commands/mr_common.cpp
+++ b/src/mongo/db/commands/mr_common.cpp
@@ -168,7 +168,7 @@ auto translateFinalize(boost::intrusive_ptr<ExpressionContext> expCtx,
auto translateOutReplace(boost::intrusive_ptr<ExpressionContext> expCtx,
NamespaceString targetNss) {
- return DocumentSourceOut::createAndAllowDifferentDB(std::move(targetNss), expCtx);
+ return DocumentSourceOut::create(std::move(targetNss), expCtx);
}
auto translateOutMerge(boost::intrusive_ptr<ExpressionContext> expCtx,
diff --git a/src/mongo/db/pipeline/document_source_out.cpp b/src/mongo/db/pipeline/document_source_out.cpp
index f5d2388cae3..ec78b9084d3 100644
--- a/src/mongo/db/pipeline/document_source_out.cpp
+++ b/src/mongo/db/pipeline/document_source_out.cpp
@@ -53,9 +53,6 @@ MONGO_FAIL_POINT_DEFINE(outWaitAfterTempCollectionCreation);
REGISTER_DOCUMENT_SOURCE(out,
DocumentSourceOut::LiteParsed::parse,
DocumentSourceOut::createFromBson);
-REGISTER_DOCUMENT_SOURCE(internalOutToDifferentDB,
- DocumentSourceOut::LiteParsed::parseToDifferentDB,
- DocumentSourceOut::createFromBsonToDifferentDB);
DocumentSourceOut::~DocumentSourceOut() {
DESTRUCTOR_GUARD(
@@ -76,35 +73,32 @@ DocumentSourceOut::~DocumentSourceOut() {
});
}
-std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::parseToDifferentDB(
- const NamespaceString& nss, const BSONElement& spec) {
-
- auto specObj = spec.Obj();
- auto dbElem = specObj["db"];
- auto collElem = specObj["coll"];
- uassert(16994,
- str::stream() << kStageName << " must have db and coll string arguments",
- dbElem.type() == BSONType::String && collElem.type() == BSONType::String);
- NamespaceString targetNss{dbElem.String(), collElem.String()};
- uassert(ErrorCodes::InvalidNamespace,
- "Invalid {} target namespace, {}"_format(kStageName, targetNss.ns()),
- targetNss.isValid());
-
- return std::make_unique<DocumentSourceOut::LiteParsed>(spec.fieldName(), std::move(targetNss));
+NamespaceString DocumentSourceOut::parseNsFromElem(const BSONElement& spec,
+ const StringData& defaultDB) {
+ if (spec.type() == BSONType::String) {
+ return NamespaceString(defaultDB, spec.valueStringData());
+ } else if (spec.type() == BSONType::Object) {
+ auto nsObj = spec.Obj();
+ uassert(16994,
+ str::stream() << kStageName << " $out must have only db and coll string arguments",
+ nsObj.nFields() == 2 && nsObj.hasField("coll") && nsObj.hasField("db"));
+ return NamespaceString(nsObj["db"].String(), nsObj["coll"].String());
+ } else {
+ uassert(16990,
+ "{} only supports a string or object argument, but found {}"_format(
+ kStageName, typeName(spec.type())),
+ spec.type() == BSONType::String);
+ }
+ MONGO_UNREACHABLE;
}
std::unique_ptr<DocumentSourceOut::LiteParsed> DocumentSourceOut::LiteParsed::parse(
const NamespaceString& nss, const BSONElement& spec) {
- uassert(16990,
- "{} only supports a string argument, but found {}"_format(kStageName,
- typeName(spec.type())),
- spec.type() == BSONType::String);
- NamespaceString targetNss{nss.db(), spec.valueStringData()};
+ NamespaceString targetNss = parseNsFromElem(spec, nss.db());
uassert(ErrorCodes::InvalidNamespace,
"Invalid {} target namespace, {}"_format(kStageName, targetNss.ns()),
targetNss.isValid());
-
return std::make_unique<DocumentSourceOut::LiteParsed>(spec.fieldName(), std::move(targetNss));
}
@@ -188,16 +182,6 @@ void DocumentSourceOut::finalize() {
boost::intrusive_ptr<DocumentSource> DocumentSourceOut::create(
NamespaceString outputNs, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
- // TODO (SERVER-36832): Allow this combination.
- uassert(50939,
- "{} is not supported when the output collection is in a different "
- "database"_format(kStageName),
- outputNs.db() == expCtx->ns.db());
- return createAndAllowDifferentDB(outputNs, expCtx);
-}
-
-boost::intrusive_ptr<DocumentSource> DocumentSourceOut::createAndAllowDifferentDB(
- NamespaceString outputNs, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
uassert(ErrorCodes::OperationNotSupportedInTransaction,
"{} cannot be used in a transaction"_format(kStageName),
!expCtx->inMultiDocumentTransaction);
@@ -219,24 +203,12 @@ boost::intrusive_ptr<DocumentSource> DocumentSourceOut::createAndAllowDifferentD
boost::intrusive_ptr<DocumentSource> DocumentSourceOut::createFromBson(
BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
- uassert(31278,
- "{} only supports a string argument, but found {}"_format(kStageName,
- typeName(elem.type())),
- elem.type() == BSONType::String);
- return create({expCtx->ns.db(), elem.str()}, expCtx);
+ auto targetNS = parseNsFromElem(elem, expCtx->ns.db());
+ return create(targetNS, expCtx);
}
-boost::intrusive_ptr<DocumentSource> DocumentSourceOut::createFromBsonToDifferentDB(
- BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& expCtx) {
-
- auto nsObj = elem.Obj();
- return createAndAllowDifferentDB(NamespaceString(nsObj["db"].String(), nsObj["coll"].String()),
- expCtx);
-}
Value DocumentSourceOut::serialize(boost::optional<ExplainOptions::Verbosity> explain) const {
- return _toDifferentDB
- ? Value(DOC(getSourceName() << DOC("db" << _outputNs.db() << "coll" << _outputNs.coll())))
- : Value(DOC(getSourceName() << _outputNs.coll()));
+ return Value(DOC(kStageName << DOC("db" << _outputNs.db() << "coll" << _outputNs.coll())));
}
void DocumentSourceOut::waitWhileFailPointEnabled() {
diff --git a/src/mongo/db/pipeline/document_source_out.h b/src/mongo/db/pipeline/document_source_out.h
index a8466f51fc4..8ff910ac007 100644
--- a/src/mongo/db/pipeline/document_source_out.h
+++ b/src/mongo/db/pipeline/document_source_out.h
@@ -38,7 +38,6 @@ namespace mongo {
class DocumentSourceOut final : public DocumentSourceWriter<BSONObj> {
public:
static constexpr StringData kStageName = "$out"_sd;
- static constexpr StringData kInternalStageName = "$internalOutToDifferentDB"_sd;
/**
* A "lite parsed" $out stage is similar to other stages involving foreign collections except in
@@ -51,9 +50,6 @@ public:
static std::unique_ptr<LiteParsed> parse(const NamespaceString& nss,
const BSONElement& spec);
- static std::unique_ptr<LiteParsed> parseToDifferentDB(const NamespaceString& nss,
- const BSONElement& spec);
-
bool allowShardedForeignCollection(NamespaceString nss) const final {
return _foreignNss != nss;
}
@@ -82,13 +78,6 @@ public:
~DocumentSourceOut() override;
- const char* getSourceName() const final override {
- if (_toDifferentDB) {
- return kInternalStageName.rawData();
- }
- return kStageName.rawData();
- }
-
StageConstraints constraints(Pipeline::SplitState pipeState) const final override {
return {StreamType::kStreaming,
PositionRequirement::kLast,
@@ -104,30 +93,23 @@ public:
boost::optional<ExplainOptions::Verbosity> explain = boost::none) const final override;
/**
- * Creates a new $out or $internalOutToDifferentDB stage from the given arguments.
+ * Creates a new $out stage from the given arguments.
*/
static boost::intrusive_ptr<DocumentSource> create(
NamespaceString outputNs, const boost::intrusive_ptr<ExpressionContext>& expCtx);
- static boost::intrusive_ptr<DocumentSource> createAndAllowDifferentDB(
- NamespaceString outputNs, const boost::intrusive_ptr<ExpressionContext>& expCtx);
-
/**
- * Parses a $out or $internalOutToDifferentDB stage from the user-supplied BSON.
+ * Parses a $out stage from the user-supplied BSON.
*/
static boost::intrusive_ptr<DocumentSource> createFromBson(
BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& pExpCtx);
- static boost::intrusive_ptr<DocumentSource> createFromBsonToDifferentDB(
- BSONElement elem, const boost::intrusive_ptr<ExpressionContext>& pExpCtx);
private:
DocumentSourceOut(NamespaceString outputNs,
const boost::intrusive_ptr<ExpressionContext>& expCtx)
- : DocumentSourceWriter(outputNs.db() == expCtx->ns.db() ? kStageName.rawData()
- : kInternalStageName.rawData(),
- std::move(outputNs),
- expCtx),
- _toDifferentDB(getOutputNs().db() != expCtx->ns.db()) {}
+ : DocumentSourceWriter(kStageName.rawData(), std::move(outputNs), expCtx) {}
+
+ static NamespaceString parseNsFromElem(const BSONElement& spec, const StringData& defaultDB);
void initialize() override;
@@ -155,10 +137,6 @@ private:
// The temporary namespace for the $out writes.
NamespaceString _tempNs;
-
- // Keep track of whether this document source is writing to a different DB for serialization
- // purposes.
- bool _toDifferentDB;
};
} // namespace mongo
diff --git a/src/mongo/db/pipeline/document_source_out_test.cpp b/src/mongo/db/pipeline/document_source_out_test.cpp
index a1cf3722676..aef9be321f0 100644
--- a/src/mongo/db/pipeline/document_source_out_test.cpp
+++ b/src/mongo/db/pipeline/document_source_out_test.cpp
@@ -85,13 +85,13 @@ public:
TEST_F(DocumentSourceOutTest, FailsToParseIncorrectType) {
BSONObj spec = BSON("$out" << 1);
- ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 31278);
+ ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 16990);
spec = BSON("$out" << BSONArray());
- ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 31278);
+ ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 16990);
spec = BSON("$out" << BSONObj());
- ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 31278);
+ ASSERT_THROWS_CODE(createOutStage(spec), AssertionException, 16994);
}
TEST_F(DocumentSourceOutTest, AcceptsStringArgument) {
@@ -106,12 +106,12 @@ TEST_F(DocumentSourceOutTest, SerializeToString) {
<< "some_collection");
auto outStage = createOutStage(spec);
auto serialized = outStage->serialize().getDocument();
- ASSERT_EQ(serialized["$out"].getStringData(), "some_collection");
+ ASSERT_EQ(serialized["$out"]["coll"].getStringData(), "some_collection");
// Make sure we can reparse the serialized BSON.
auto reparsedOutStage = createOutStage(serialized.toBson());
auto reSerialized = reparsedOutStage->serialize().getDocument();
- ASSERT_EQ(reSerialized["$out"].getStringData(), "some_collection");
+ ASSERT_EQ(reSerialized["$out"]["coll"].getStringData(), "some_collection");
}
} // namespace
diff --git a/src/mongo/db/pipeline/pipeline_test.cpp b/src/mongo/db/pipeline/pipeline_test.cpp
index 912d96fe49f..870717b4624 100644
--- a/src/mongo/db/pipeline/pipeline_test.cpp
+++ b/src/mongo/db/pipeline/pipeline_test.cpp
@@ -2573,7 +2573,7 @@ class Out : public ShardMergerBase {
return "[]";
}
string mergePipeJson() {
- return "[{$out: 'outColl'}]";
+ return "[{$out: {db: 'a', coll: 'outColl'}}]";
}
};