/** * Test aggregation explain of $merge and $out pipelines. * * The $out stage is not allowed with a sharded output collection. Explain of $out or $merge does * not accept writeConcern. * @tags: [ * assumes_unsharded_collection, * assumes_write_concern_unchanged, * ] */ import {withEachMergeMode} from "jstests/aggregation/extras/merge_helpers.js"; import {getExplainPipelineFromAggregationResult} from "jstests/aggregation/extras/utils.js"; let sourceColl = db.explain_writing_aggs_source; let targetColl = db.explain_writing_aggs_target; sourceColl.drop(); targetColl.drop(); assert.commandWorked(sourceColl.insert({_id: 1})); // Verifies that running the execution explains do not error, perform any writes, or create the // target collection. function assertExecutionExplainOk(writingStage, verbosity) { assert.commandWorked( db.runCommand({ explain: {aggregate: sourceColl.getName(), pipeline: [writingStage], cursor: {}}, verbosity: verbosity, }), ); assert.eq(targetColl.find().itcount(), 0); // Verify that the collection was not created. const collectionList = db.getCollectionInfos({name: targetColl.getName()}); assert.eq(0, collectionList.length, collectionList); } // Test that $out can be explained with 'queryPlanner' explain verbosity and does not perform // any writes. let explain = sourceColl.explain("queryPlanner").aggregate([{$out: targetColl.getName()}]); let explainedPipeline = getExplainPipelineFromAggregationResult(explain, {inhibitOptimization: false}); assert.eq(1, explainedPipeline.length); assert(explainedPipeline[0].$out); let outExplain = explainedPipeline[0]; assert.neq(outExplain, null, 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. assertExecutionExplainOk({$out: targetColl.getName()}, "executionStats"); assertExecutionExplainOk({$out: targetColl.getName()}, "allPlansExecution"); // Test each $merge mode with each explain verbosity. withEachMergeMode(function ({whenMatchedMode, whenNotMatchedMode}) { const mergeStage = { $merge: { into: targetColl.getName(), whenMatched: whenMatchedMode, whenNotMatched: whenNotMatchedMode, }, }; // Verify that execution explains don't error for $merge. assertExecutionExplainOk(mergeStage, "executionStats"); assertExecutionExplainOk(mergeStage, "allPlansExecution"); const explain = sourceColl.explain("queryPlanner").aggregate([mergeStage]); let explainedPipeline = getExplainPipelineFromAggregationResult(explain, {inhibitOptimization: false}); assert.eq(1, explainedPipeline.length); assert(explainedPipeline[0].$merge); const mergeExplain = explainedPipeline[0]; assert.neq(mergeExplain, null, explain); assert(mergeExplain.hasOwnProperty("$merge"), explain); assert.eq(mergeExplain.$merge.whenMatched, whenMatchedMode, mergeExplain); assert.eq(mergeExplain.$merge.whenNotMatched, whenNotMatchedMode, mergeExplain); assert.eq(mergeExplain.$merge.on, "_id", mergeExplain); assert.eq(targetColl.find().itcount(), 0, explain); });