41
41
#include " mongo/db/commands.h"
42
42
#include " mongo/db/commands/map_reduce_agg.h"
43
43
#include " mongo/db/commands/map_reduce_javascript_code.h"
44
+ #include " mongo/db/commands/mr_common.h"
44
45
#include " mongo/db/db_raii.h"
45
46
#include " mongo/db/exec/document_value/value.h"
46
47
#include " mongo/db/namespace_string.h"
47
- #include " mongo/db/pipeline/document_source.h"
48
- #include " mongo/db/pipeline/document_source_group.h"
49
- #include " mongo/db/pipeline/document_source_limit.h"
50
- #include " mongo/db/pipeline/document_source_match.h"
51
- #include " mongo/db/pipeline/document_source_merge.h"
52
- #include " mongo/db/pipeline/document_source_out.h"
53
- #include " mongo/db/pipeline/document_source_project.h"
54
- #include " mongo/db/pipeline/document_source_single_document_transformation.h"
55
- #include " mongo/db/pipeline/document_source_sort.h"
56
- #include " mongo/db/pipeline/document_source_unwind.h"
57
48
#include " mongo/db/pipeline/expression.h"
58
- #include " mongo/db/pipeline/expression_javascript.h"
59
- #include " mongo/db/pipeline/parsed_aggregation_projection_node.h"
60
- #include " mongo/db/pipeline/parsed_inclusion_projection.h"
61
49
#include " mongo/db/pipeline/pipeline_d.h"
62
50
#include " mongo/db/query/map_reduce_output_format.h"
63
- #include " mongo/db/query/util/make_data_structure.h"
64
- #include " mongo/util/intrusive_counter.h"
65
51
66
52
namespace mongo ::map_reduce_agg {
67
53
68
54
namespace {
69
55
70
- using namespace std ::string_literals;
71
-
72
- auto translateSort (boost::intrusive_ptr<ExpressionContext> expCtx,
73
- const BSONObj& sort,
74
- const boost::optional<std::int64_t >& limit) {
75
- return DocumentSourceSort::create (expCtx, sort, limit.get_value_or (-1 ));
76
- }
77
-
78
- auto translateMap (boost::intrusive_ptr<ExpressionContext> expCtx, std::string code) {
79
- auto emitExpression = ExpressionInternalJsEmit::create (
80
- expCtx, ExpressionFieldPath::parse (expCtx, " $$ROOT" , expCtx->variablesParseState ), code);
81
- auto node = std::make_unique<parsed_aggregation_projection::InclusionNode>(
82
- ProjectionPolicies{ProjectionPolicies::DefaultIdPolicy::kExcludeId });
83
- node->addExpressionForPath (FieldPath{" emits" s}, std::move (emitExpression));
84
- auto inclusion = std::unique_ptr<TransformerInterface>{
85
- std::make_unique<parsed_aggregation_projection::ParsedInclusionProjection>(
86
- expCtx,
87
- ProjectionPolicies{ProjectionPolicies::DefaultIdPolicy::kExcludeId },
88
- std::move (node))};
89
- return make_intrusive<DocumentSourceSingleDocumentTransformation>(
90
- expCtx, std::move (inclusion), DocumentSourceProject::kStageName , false );
91
- }
92
-
93
- auto translateReduce (boost::intrusive_ptr<ExpressionContext> expCtx, std::string code) {
94
- auto accumulatorArguments = ExpressionObject::create (
95
- expCtx,
96
- make_vector<std::pair<std::string, boost::intrusive_ptr<Expression>>>(
97
- std::pair{" data" s,
98
- ExpressionFieldPath::parse (expCtx, " $emits" , expCtx->variablesParseState )},
99
- std::pair{" eval" s, ExpressionConstant::create (expCtx, Value{code})}));
100
- auto jsReduce = AccumulationStatement{
101
- " value" ,
102
- std::move (accumulatorArguments),
103
- AccumulationStatement::getFactory (AccumulatorInternalJsReduce::kAccumulatorName )};
104
- auto groupExpr = ExpressionFieldPath::parse (expCtx, " $emits.k" , expCtx->variablesParseState );
105
- return DocumentSourceGroup::create (expCtx,
106
- std::move (groupExpr),
107
- make_vector<AccumulationStatement>(std::move (jsReduce)),
108
- boost::none);
109
- }
110
-
111
- auto translateFinalize (boost::intrusive_ptr<ExpressionContext> expCtx, std::string code) {
112
- auto jsExpression = ExpressionInternalJs::create (
113
- expCtx,
114
- ExpressionArray::create (
115
- expCtx,
116
- make_vector<boost::intrusive_ptr<Expression>>(
117
- ExpressionFieldPath::parse (expCtx, " $_id" , expCtx->variablesParseState ),
118
- ExpressionFieldPath::parse (expCtx, " $value" , expCtx->variablesParseState ))),
119
- code);
120
- auto node = std::make_unique<parsed_aggregation_projection::InclusionNode>(
121
- ProjectionPolicies{ProjectionPolicies::DefaultIdPolicy::kExcludeId });
122
- node->addExpressionForPath (FieldPath{" value" s}, std::move (jsExpression));
123
- auto inclusion = std::unique_ptr<TransformerInterface>{
124
- std::make_unique<parsed_aggregation_projection::ParsedInclusionProjection>(
125
- expCtx,
126
- ProjectionPolicies{ProjectionPolicies::DefaultIdPolicy::kExcludeId },
127
- std::move (node))};
128
- return make_intrusive<DocumentSourceSingleDocumentTransformation>(
129
- expCtx, std::move (inclusion), DocumentSourceProject::kStageName , false );
130
- }
131
-
132
- auto translateOutReplace (boost::intrusive_ptr<ExpressionContext> expCtx,
133
- const StringData inputDatabase,
134
- NamespaceString targetNss) {
135
- uassert (31278 ,
136
- " MapReduce must output to the database belonging to its input collection - Input: " s +
137
- inputDatabase + " Output: " + targetNss.db (),
138
- inputDatabase == targetNss.db ());
139
- return DocumentSourceOut::create (std::move (targetNss), expCtx);
140
- }
141
-
142
- auto translateOutMerge (boost::intrusive_ptr<ExpressionContext> expCtx, NamespaceString targetNss) {
143
- return DocumentSourceMerge::create (targetNss,
144
- expCtx,
145
- MergeWhenMatchedModeEnum::kReplace ,
146
- MergeWhenNotMatchedModeEnum::kInsert ,
147
- boost::none, // Let variables
148
- boost::none, // pipeline
149
- std::set<FieldPath>{FieldPath (" _id" s)},
150
- boost::none); // targetCollectionVersion
151
- }
152
-
153
- auto translateOutReduce (boost::intrusive_ptr<ExpressionContext> expCtx,
154
- NamespaceString targetNss,
155
- std::string code) {
156
- // Because of communication for sharding, $merge must hold on to a serializable BSON object
157
- // at the moment so we reparse here.
158
- auto reduceObj = BSON (" args" << BSON_ARRAY (" $value"
159
- << " $$new.value" )
160
- << " eval" << code);
161
-
162
- auto finalProjectSpec =
163
- BSON (DocumentSourceProject::kStageName
164
- << BSON (" value" << BSON (ExpressionInternalJs::kExpressionName << reduceObj)));
165
- auto pipelineSpec = boost::make_optional (std::vector<BSONObj>{finalProjectSpec});
166
- return DocumentSourceMerge::create (targetNss,
167
- expCtx,
168
- MergeWhenMatchedModeEnum::kPipeline ,
169
- MergeWhenNotMatchedModeEnum::kInsert ,
170
- boost::none, // Let variables
171
- pipelineSpec,
172
- std::set<FieldPath>{FieldPath (" _id" s)},
173
- boost::none); // targetCollectionVersion
174
- }
175
-
176
- auto translateOut (boost::intrusive_ptr<ExpressionContext> expCtx,
177
- const OutputType outputType,
178
- const StringData inputDatabase,
179
- NamespaceString targetNss,
180
- std::string reduceCode) {
181
- switch (outputType) {
182
- case OutputType::Replace:
183
- return boost::make_optional (translateOutReplace (expCtx, inputDatabase, targetNss));
184
- case OutputType::Merge:
185
- return boost::make_optional (translateOutMerge (expCtx, targetNss));
186
- case OutputType::Reduce:
187
- return boost::make_optional (translateOutReduce (expCtx, targetNss, reduceCode));
188
- case OutputType::InMemory:;
189
- }
190
- return boost::optional<boost::intrusive_ptr<mongo::DocumentSource>>{};
191
- }
192
-
193
56
auto makeExpressionContext (OperationContext* opCtx, const MapReduce& parsedMr) {
194
57
// AutoGetCollectionForReadCommand will throw if the sharding version for this connection is
195
58
// out of date.
@@ -247,7 +110,7 @@ bool runAggregationMapReduce(OperationContext* opCtx,
247
110
auto parsedMr = MapReduce::parse (IDLParserErrorContext (" MapReduce" ), cmd);
248
111
auto expCtx = makeExpressionContext (opCtx, parsedMr);
249
112
auto runnablePipeline = [&]() {
250
- auto pipeline = translateFromMR (parsedMr, expCtx);
113
+ auto pipeline = map_reduce_common:: translateFromMR (parsedMr, expCtx);
251
114
return expCtx->mongoProcessInterface ->attachCursorSourceToPipelineForLocalRead (
252
115
expCtx, pipeline.release ());
253
116
}();
@@ -274,32 +137,4 @@ bool runAggregationMapReduce(OperationContext* opCtx,
274
137
return true ;
275
138
}
276
139
277
- std::unique_ptr<Pipeline, PipelineDeleter> translateFromMR (
278
- MapReduce parsedMr, boost::intrusive_ptr<ExpressionContext> expCtx) {
279
-
280
- // TODO: It would be good to figure out what kind of errors this would produce in the Status.
281
- // It would be better not to produce something incomprehensible out of an internal translation.
282
- return uassertStatusOK (Pipeline::create (
283
- makeFlattenedList<boost::intrusive_ptr<DocumentSource>>(
284
- parsedMr.getQuery ().map (
285
- [&](auto && query) { return DocumentSourceMatch::create (query, expCtx); }),
286
- parsedMr.getSort ().map (
287
- [&](auto && sort) { return translateSort (expCtx, sort, parsedMr.getLimit ()); }),
288
- translateMap (expCtx, parsedMr.getMap ().getCode ()),
289
- DocumentSourceUnwind::create (expCtx, " emits" , false , boost::none),
290
- translateReduce (expCtx, parsedMr.getReduce ().getCode ()),
291
- parsedMr.getFinalize ().map ([&](auto && finalize) {
292
- return translateFinalize (expCtx, parsedMr.getFinalize ()->getCode ());
293
- }),
294
- translateOut (expCtx,
295
- parsedMr.getOutOptions ().getOutputType (),
296
- parsedMr.getNamespace ().db (),
297
- NamespaceString{parsedMr.getOutOptions ().getDatabaseName ()
298
- ? *parsedMr.getOutOptions ().getDatabaseName ()
299
- : parsedMr.getNamespace ().db (),
300
- parsedMr.getOutOptions ().getCollectionName ()},
301
- parsedMr.getReduce ().getCode ())),
302
- expCtx));
303
- }
304
-
305
140
} // namespace mongo::map_reduce_agg
0 commit comments