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