1 
2 /**
3  *    Copyright (C) 2018-present MongoDB, Inc.
4  *
5  *    This program is free software: you can redistribute it and/or modify
6  *    it under the terms of the Server Side Public License, version 1,
7  *    as published by MongoDB, Inc.
8  *
9  *    This program is distributed in the hope that it will be useful,
10  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  *    Server Side Public License for more details.
13  *
14  *    You should have received a copy of the Server Side Public License
15  *    along with this program. If not, see
16  *    <http://www.mongodb.com/licensing/server-side-public-license>.
17  *
18  *    As a special exception, the copyright holders give permission to link the
19  *    code of portions of this program with the OpenSSL library under certain
20  *    conditions as described in each individual source file and distribute
21  *    linked combinations including the program with the OpenSSL library. You
22  *    must comply with the Server Side Public License in all respects for
23  *    all of the code used other than as permitted herein. If you modify file(s)
24  *    with this exception, you may extend this exception to your version of the
25  *    file(s), but you are not obligated to do so. If you do not wish to do so,
26  *    delete this exception statement from your version. If you delete this
27  *    exception statement from all source files in the program, then also delete
28  *    it in the license file.
29  */
30 
31 #pragma once
32 
33 #include "mongo/bson/simple_bsonobj_comparator.h"
34 #include "mongo/db/exec/plan_stage.h"
35 #include "mongo/db/namespace_string.h"
36 #include "mongo/scripting/engine.h"
37 
38 namespace mongo {
39 
40 class Collection;
41 
42 /**
43  * A description of a request for a group operation.  Copyable.
44  */
45 struct GroupRequest {
46     // Namespace to operate on (e.g. "foo.bar").
47     NamespaceString ns;
48 
49     // A predicate describing the set of documents to group.
50     BSONObj query;
51 
52     // The field(s) to group by.  Alternative to "keyFunctionCode".  Empty if "keyFunctionCode"
53     // is being used instead.
54     BSONObj keyPattern;
55 
56     // A Javascript function that maps a document to a key object.  Alternative to "keyPattern".
57     // Empty is "keyPattern" is being used instead.
58     std::string keyFunctionCode;
59 
60     // The collation used for string comparisons. If empty, simple binary comparison with memcmp()
61     // is used.
62     BSONObj collation;
63 
64     // A Javascript function that takes a (input document, group result) pair and
65     // updates the group result document.
66     std::string reduceCode;
67 
68     // Scope for the reduce function.  Optional.
69     BSONObj reduceScope;
70 
71     // The initial value for the group result.
72     BSONObj initial;
73 
74     // A Javascript function that "finalizes" a group result.  Optional.
75     std::string finalize;
76 
77     // Whether this is an explain of a group.
78     bool explain;
79 };
80 
81 /**
82  * Stage used by the group command.  Consumes input documents from its child stage (returning
83  * NEED_TIME once for each document produced by the child), returns ADVANCED exactly once with
84  * the entire group result, then returns EOF.
85  *
86  * Only created through the getExecutorGroup path.
87  */
88 class GroupStage final : public PlanStage {
89     MONGO_DISALLOW_COPYING(GroupStage);
90 
91 public:
92     GroupStage(OperationContext* opCtx,
93                const GroupRequest& request,
94                WorkingSet* workingSet,
95                PlanStage* child);
96 
97     StageState doWork(WorkingSetID* out) final;
98     bool isEOF() final;
99 
stageType()100     StageType stageType() const final {
101         return STAGE_GROUP;
102     }
103 
104     std::unique_ptr<PlanStageStats> getStats() final;
105 
106     const SpecificStats* getSpecificStats() const final;
107 
108     static const char* kStageType;
109 
110 private:
111     /**
112      * Keeps track of what this group is currently doing so that it can do the right thing on
113      * the next call to work().
114      */
115     enum GroupState {
116         // Need to initialize the underlying Javascript machinery.
117         GroupState_Initializing,
118 
119         // Retrieving the next document from the child stage and processing it.
120         GroupState_ReadingFromChild,
121 
122         // Results have been returned.
123         GroupState_Done
124     };
125 
126     // Initializes _scope, _reduceFunction and _keyFunction using the global scripting engine.
127     Status initGroupScripting();
128 
129     // Updates _groupMap and _scope to account for the group key associated with this object.
130     // Returns an error status if an error occurred, else Status::OK().
131     Status processObject(const BSONObj& obj);
132 
133     // Finalize the results for this group operation. On success, returns with a BSONObj with
134     // the results array. On failure, returns a non-OK status. Does not throw.
135     StatusWith<BSONObj> finalizeResults();
136 
137     GroupRequest _request;
138 
139     // The WorkingSet we annotate with results.  Not owned by us.
140     WorkingSet* _ws;
141 
142     GroupStats _specificStats;
143 
144     // Current state for this stage.
145     GroupState _groupState;
146 
147     // The Scope object that all script operations for this group stage will use.  Initialized
148     // by initGroupScripting().  Owned here.
149     std::unique_ptr<Scope> _scope;
150 
151     // The reduce function for the group operation.  Initialized by initGroupScripting().  Owned
152     // by _scope.
153     ScriptingFunction _reduceFunction;
154 
155     // The key function for the group operation if one was provided by the user, else 0.
156     // Initialized by initGroupScripting().  Owned by _scope.
157     ScriptingFunction _keyFunction;
158 
159     // Map from group key => group index.  The group index is used to index into "$arr", a
160     // variable owned by _scope which contains the group data for this key.
161     BSONObjIndexedMap<int> _groupMap;
162 };
163 
164 }  // namespace mongo
165