mirror of
https://github.com/mongodb/mongo.git
synced 2024-12-01 09:32:32 +01:00
moving some commands into db/commands/ directory
This commit is contained in:
parent
cddcb6d164
commit
f550177b1a
@ -452,6 +452,7 @@ serverOnlyFiles = Split( "db/query.cpp db/update.cpp db/introspect.cpp db/btree.
|
||||
serverOnlyFiles += [ "db/index.cpp" ] + Glob( "db/geo/*.cpp" )
|
||||
|
||||
serverOnlyFiles += [ "db/dbcommands.cpp" , "db/dbcommands_admin.cpp" ]
|
||||
serverOnlyFiles += Glob( "db/commands/*.cpp" )
|
||||
coreServerFiles += Glob( "db/stats/*.cpp" )
|
||||
serverOnlyFiles += [ "db/driverHelpers.cpp" ]
|
||||
|
||||
|
75
db/commands/distinct.cpp
Normal file
75
db/commands/distinct.cpp
Normal file
@ -0,0 +1,75 @@
|
||||
// distinct.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include "../commands.h"
|
||||
#include "../instance.h"
|
||||
#include "../queryoptimizer.h"
|
||||
#include "../clientcursor.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
class DistinctCommand : public Command {
|
||||
public:
|
||||
DistinctCommand() : Command("distinct"){}
|
||||
virtual bool slaveOk() const { return true; }
|
||||
virtual LockType locktype() const { return READ; }
|
||||
virtual void help( stringstream &help ) const {
|
||||
help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }";
|
||||
}
|
||||
|
||||
bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
string ns = dbname + '.' + cmdObj.firstElement().valuestr();
|
||||
|
||||
string key = cmdObj["key"].valuestrsafe();
|
||||
BSONObj keyPattern = BSON( key << 1 );
|
||||
|
||||
BSONObj query = getQuery( cmdObj );
|
||||
|
||||
BSONElementSet values;
|
||||
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
|
||||
scoped_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns));
|
||||
|
||||
while ( cursor->ok() ){
|
||||
if ( !cursor->matcher() || cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
BSONObj o = cursor->current();
|
||||
o.getFieldsDotted( key, values );
|
||||
}
|
||||
|
||||
cursor->advance();
|
||||
|
||||
if (!cc->yieldSometimes())
|
||||
break;
|
||||
|
||||
RARELY killCurrentOp.checkForInterrupt();
|
||||
}
|
||||
|
||||
BSONArrayBuilder b( result.subarrayStart( "values" ) );
|
||||
for ( BSONElementSet::iterator i = values.begin() ; i != values.end(); i++ ){
|
||||
b.append( *i );
|
||||
}
|
||||
BSONObj arr = b.done();
|
||||
|
||||
uassert(10044, "distinct too big, 4mb cap",
|
||||
(arr.objsize() + 1024) < (4 * 1024 * 1024));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} distinctCmd;
|
||||
|
||||
}
|
202
db/commands/group.cpp
Normal file
202
db/commands/group.cpp
Normal file
@ -0,0 +1,202 @@
|
||||
// group.cpp
|
||||
|
||||
/**
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3,
|
||||
* as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "pch.h"
|
||||
#include "../commands.h"
|
||||
#include "../instance.h"
|
||||
#include "../queryoptimizer.h"
|
||||
|
||||
namespace mongo {
|
||||
|
||||
class GroupCommand : public Command {
|
||||
public:
|
||||
GroupCommand() : Command("group"){}
|
||||
virtual LockType locktype() const { return READ; }
|
||||
virtual bool slaveOk() const { return true; }
|
||||
virtual bool slaveOverrideOk() { return true; }
|
||||
virtual void help( stringstream &help ) const {
|
||||
help << "http://www.mongodb.org/display/DOCS/Aggregation";
|
||||
}
|
||||
|
||||
BSONObj getKey( const BSONObj& obj , const BSONObj& keyPattern , ScriptingFunction func , double avgSize , Scope * s ){
|
||||
if ( func ){
|
||||
BSONObjBuilder b( obj.objsize() + 32 );
|
||||
b.append( "0" , obj );
|
||||
int res = s->invoke( func , b.obj() );
|
||||
uassert( 10041 , (string)"invoke failed in $keyf: " + s->getError() , res == 0 );
|
||||
int type = s->type("return");
|
||||
uassert( 10042 , "return of $key has to be an object" , type == Object );
|
||||
return s->getObject( "return" );
|
||||
}
|
||||
return obj.extractFields( keyPattern , true );
|
||||
}
|
||||
|
||||
bool group( string realdbname , const string& ns , const BSONObj& query ,
|
||||
BSONObj keyPattern , string keyFunctionCode , string reduceCode , const char * reduceScope ,
|
||||
BSONObj initial , string finalize ,
|
||||
string& errmsg , BSONObjBuilder& result ){
|
||||
|
||||
|
||||
auto_ptr<Scope> s = globalScriptEngine->getPooledScope( realdbname );
|
||||
s->localConnect( realdbname.c_str() );
|
||||
|
||||
if ( reduceScope )
|
||||
s->init( reduceScope );
|
||||
|
||||
s->setObject( "$initial" , initial , true );
|
||||
|
||||
s->exec( "$reduce = " + reduceCode , "reduce setup" , false , true , true , 100 );
|
||||
s->exec( "$arr = [];" , "reduce setup 2" , false , true , true , 100 );
|
||||
ScriptingFunction f = s->createFunction(
|
||||
"function(){ "
|
||||
" if ( $arr[n] == null ){ "
|
||||
" next = {}; "
|
||||
" Object.extend( next , $key ); "
|
||||
" Object.extend( next , $initial , true ); "
|
||||
" $arr[n] = next; "
|
||||
" next = null; "
|
||||
" } "
|
||||
" $reduce( obj , $arr[n] ); "
|
||||
"}" );
|
||||
|
||||
ScriptingFunction keyFunction = 0;
|
||||
if ( keyFunctionCode.size() ){
|
||||
keyFunction = s->createFunction( keyFunctionCode.c_str() );
|
||||
}
|
||||
|
||||
|
||||
double keysize = keyPattern.objsize() * 3;
|
||||
double keynum = 1;
|
||||
|
||||
map<BSONObj,int,BSONObjCmp> map;
|
||||
list<BSONObj> blah;
|
||||
|
||||
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
|
||||
|
||||
while ( cursor->ok() ){
|
||||
if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
cursor->advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
BSONObj obj = cursor->current();
|
||||
cursor->advance();
|
||||
|
||||
BSONObj key = getKey( obj , keyPattern , keyFunction , keysize / keynum , s.get() );
|
||||
keysize += key.objsize();
|
||||
keynum++;
|
||||
|
||||
int& n = map[key];
|
||||
if ( n == 0 ){
|
||||
n = map.size();
|
||||
s->setObject( "$key" , key , true );
|
||||
|
||||
uassert( 10043 , "group() can't handle more than 10000 unique keys" , n <= 10000 );
|
||||
}
|
||||
|
||||
s->setObject( "obj" , obj , true );
|
||||
s->setNumber( "n" , n - 1 );
|
||||
if ( s->invoke( f , BSONObj() , 0 , true ) ){
|
||||
throw UserException( 9010 , (string)"reduce invoke failed: " + s->getError() );
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalize.empty()){
|
||||
s->exec( "$finalize = " + finalize , "finalize define" , false , true , true , 100 );
|
||||
ScriptingFunction g = s->createFunction(
|
||||
"function(){ "
|
||||
" for(var i=0; i < $arr.length; i++){ "
|
||||
" var ret = $finalize($arr[i]); "
|
||||
" if (ret !== undefined) "
|
||||
" $arr[i] = ret; "
|
||||
" } "
|
||||
"}" );
|
||||
s->invoke( g , BSONObj() , 0 , true );
|
||||
}
|
||||
|
||||
result.appendArray( "retval" , s->getObject( "$arr" ) );
|
||||
result.append( "count" , keynum - 1 );
|
||||
result.append( "keys" , (int)(map.size()) );
|
||||
s->exec( "$arr = [];" , "reduce setup 2" , false , true , true , 100 );
|
||||
s->gc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
|
||||
/* db.$cmd.findOne( { group : <p> } ) */
|
||||
const BSONObj& p = jsobj.firstElement().embeddedObjectUserCheck();
|
||||
|
||||
BSONObj q;
|
||||
if ( p["cond"].type() == Object )
|
||||
q = p["cond"].embeddedObject();
|
||||
else if ( p["condition"].type() == Object )
|
||||
q = p["condition"].embeddedObject();
|
||||
else
|
||||
q = getQuery( p );
|
||||
|
||||
if ( p["ns"].type() != String ){
|
||||
errmsg = "ns has to be set";
|
||||
return false;
|
||||
}
|
||||
|
||||
string ns = dbname + "." + p["ns"].String();
|
||||
|
||||
BSONObj key;
|
||||
string keyf;
|
||||
if ( p["key"].type() == Object ){
|
||||
key = p["key"].embeddedObjectUserCheck();
|
||||
if ( ! p["$keyf"].eoo() ){
|
||||
errmsg = "can't have key and $keyf";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( p["$keyf"].type() ){
|
||||
keyf = p["$keyf"]._asCode();
|
||||
}
|
||||
else {
|
||||
// no key specified, will use entire object as key
|
||||
}
|
||||
|
||||
BSONElement reduce = p["$reduce"];
|
||||
if ( reduce.eoo() ){
|
||||
errmsg = "$reduce has to be set";
|
||||
return false;
|
||||
}
|
||||
|
||||
BSONElement initial = p["initial"];
|
||||
if ( initial.type() != Object ){
|
||||
errmsg = "initial has to be an object";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
string finalize;
|
||||
if (p["finalize"].type())
|
||||
finalize = p["finalize"]._asCode();
|
||||
|
||||
return group( dbname , ns , q ,
|
||||
key , keyf , reduce._asCode() , reduce.type() != CodeWScope ? 0 : reduce.codeWScopeScopeData() ,
|
||||
initial.embeddedObject() , finalize ,
|
||||
errmsg , result );
|
||||
}
|
||||
|
||||
} cmdGroup;
|
||||
|
||||
|
||||
} // namespace mongo
|
@ -1278,232 +1278,6 @@ namespace mongo {
|
||||
}
|
||||
} cmdConvertToCapped;
|
||||
|
||||
class GroupCommand : public Command {
|
||||
public:
|
||||
GroupCommand() : Command("group"){}
|
||||
virtual LockType locktype() const { return READ; }
|
||||
virtual bool slaveOk() const { return true; }
|
||||
virtual bool slaveOverrideOk() { return true; }
|
||||
virtual void help( stringstream &help ) const {
|
||||
help << "http://www.mongodb.org/display/DOCS/Aggregation";
|
||||
}
|
||||
|
||||
BSONObj getKey( const BSONObj& obj , const BSONObj& keyPattern , ScriptingFunction func , double avgSize , Scope * s ){
|
||||
if ( func ){
|
||||
BSONObjBuilder b( obj.objsize() + 32 );
|
||||
b.append( "0" , obj );
|
||||
int res = s->invoke( func , b.obj() );
|
||||
uassert( 10041 , (string)"invoke failed in $keyf: " + s->getError() , res == 0 );
|
||||
int type = s->type("return");
|
||||
uassert( 10042 , "return of $key has to be an object" , type == Object );
|
||||
return s->getObject( "return" );
|
||||
}
|
||||
return obj.extractFields( keyPattern , true );
|
||||
}
|
||||
|
||||
bool group( string realdbname , const string& ns , const BSONObj& query ,
|
||||
BSONObj keyPattern , string keyFunctionCode , string reduceCode , const char * reduceScope ,
|
||||
BSONObj initial , string finalize ,
|
||||
string& errmsg , BSONObjBuilder& result ){
|
||||
|
||||
|
||||
auto_ptr<Scope> s = globalScriptEngine->getPooledScope( realdbname );
|
||||
s->localConnect( realdbname.c_str() );
|
||||
|
||||
if ( reduceScope )
|
||||
s->init( reduceScope );
|
||||
|
||||
s->setObject( "$initial" , initial , true );
|
||||
|
||||
s->exec( "$reduce = " + reduceCode , "reduce setup" , false , true , true , 100 );
|
||||
s->exec( "$arr = [];" , "reduce setup 2" , false , true , true , 100 );
|
||||
ScriptingFunction f = s->createFunction(
|
||||
"function(){ "
|
||||
" if ( $arr[n] == null ){ "
|
||||
" next = {}; "
|
||||
" Object.extend( next , $key ); "
|
||||
" Object.extend( next , $initial , true ); "
|
||||
" $arr[n] = next; "
|
||||
" next = null; "
|
||||
" } "
|
||||
" $reduce( obj , $arr[n] ); "
|
||||
"}" );
|
||||
|
||||
ScriptingFunction keyFunction = 0;
|
||||
if ( keyFunctionCode.size() ){
|
||||
keyFunction = s->createFunction( keyFunctionCode.c_str() );
|
||||
}
|
||||
|
||||
|
||||
double keysize = keyPattern.objsize() * 3;
|
||||
double keynum = 1;
|
||||
|
||||
map<BSONObj,int,BSONObjCmp> map;
|
||||
list<BSONObj> blah;
|
||||
|
||||
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
|
||||
|
||||
while ( cursor->ok() ){
|
||||
if ( cursor->matcher() && ! cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
cursor->advance();
|
||||
continue;
|
||||
}
|
||||
|
||||
BSONObj obj = cursor->current();
|
||||
cursor->advance();
|
||||
|
||||
BSONObj key = getKey( obj , keyPattern , keyFunction , keysize / keynum , s.get() );
|
||||
keysize += key.objsize();
|
||||
keynum++;
|
||||
|
||||
int& n = map[key];
|
||||
if ( n == 0 ){
|
||||
n = map.size();
|
||||
s->setObject( "$key" , key , true );
|
||||
|
||||
uassert( 10043 , "group() can't handle more than 10000 unique keys" , n <= 10000 );
|
||||
}
|
||||
|
||||
s->setObject( "obj" , obj , true );
|
||||
s->setNumber( "n" , n - 1 );
|
||||
if ( s->invoke( f , BSONObj() , 0 , true ) ){
|
||||
throw UserException( 9010 , (string)"reduce invoke failed: " + s->getError() );
|
||||
}
|
||||
}
|
||||
|
||||
if (!finalize.empty()){
|
||||
s->exec( "$finalize = " + finalize , "finalize define" , false , true , true , 100 );
|
||||
ScriptingFunction g = s->createFunction(
|
||||
"function(){ "
|
||||
" for(var i=0; i < $arr.length; i++){ "
|
||||
" var ret = $finalize($arr[i]); "
|
||||
" if (ret !== undefined) "
|
||||
" $arr[i] = ret; "
|
||||
" } "
|
||||
"}" );
|
||||
s->invoke( g , BSONObj() , 0 , true );
|
||||
}
|
||||
|
||||
result.appendArray( "retval" , s->getObject( "$arr" ) );
|
||||
result.append( "count" , keynum - 1 );
|
||||
result.append( "keys" , (int)(map.size()) );
|
||||
s->exec( "$arr = [];" , "reduce setup 2" , false , true , true , 100 );
|
||||
s->gc();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run(const string& dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
|
||||
/* db.$cmd.findOne( { group : <p> } ) */
|
||||
const BSONObj& p = jsobj.firstElement().embeddedObjectUserCheck();
|
||||
|
||||
BSONObj q;
|
||||
if ( p["cond"].type() == Object )
|
||||
q = p["cond"].embeddedObject();
|
||||
else if ( p["condition"].type() == Object )
|
||||
q = p["condition"].embeddedObject();
|
||||
else
|
||||
q = getQuery( p );
|
||||
|
||||
if ( p["ns"].type() != String ){
|
||||
errmsg = "ns has to be set";
|
||||
return false;
|
||||
}
|
||||
|
||||
string ns = dbname + "." + p["ns"].String();
|
||||
|
||||
BSONObj key;
|
||||
string keyf;
|
||||
if ( p["key"].type() == Object ){
|
||||
key = p["key"].embeddedObjectUserCheck();
|
||||
if ( ! p["$keyf"].eoo() ){
|
||||
errmsg = "can't have key and $keyf";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if ( p["$keyf"].type() ){
|
||||
keyf = p["$keyf"]._asCode();
|
||||
}
|
||||
else {
|
||||
// no key specified, will use entire object as key
|
||||
}
|
||||
|
||||
BSONElement reduce = p["$reduce"];
|
||||
if ( reduce.eoo() ){
|
||||
errmsg = "$reduce has to be set";
|
||||
return false;
|
||||
}
|
||||
|
||||
BSONElement initial = p["initial"];
|
||||
if ( initial.type() != Object ){
|
||||
errmsg = "initial has to be an object";
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
string finalize;
|
||||
if (p["finalize"].type())
|
||||
finalize = p["finalize"]._asCode();
|
||||
|
||||
return group( dbname , ns , q ,
|
||||
key , keyf , reduce._asCode() , reduce.type() != CodeWScope ? 0 : reduce.codeWScopeScopeData() ,
|
||||
initial.embeddedObject() , finalize ,
|
||||
errmsg , result );
|
||||
}
|
||||
|
||||
} cmdGroup;
|
||||
|
||||
|
||||
class DistinctCommand : public Command {
|
||||
public:
|
||||
DistinctCommand() : Command("distinct"){}
|
||||
virtual bool slaveOk() const { return true; }
|
||||
virtual LockType locktype() const { return READ; }
|
||||
virtual void help( stringstream &help ) const {
|
||||
help << "{ distinct : 'collection name' , key : 'a.b' , query : {} }";
|
||||
}
|
||||
|
||||
bool run(const string& dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
|
||||
string ns = dbname + '.' + cmdObj.firstElement().valuestr();
|
||||
|
||||
string key = cmdObj["key"].valuestrsafe();
|
||||
BSONObj keyPattern = BSON( key << 1 );
|
||||
|
||||
BSONObj query = getQuery( cmdObj );
|
||||
|
||||
BSONElementSet values;
|
||||
shared_ptr<Cursor> cursor = bestGuessCursor(ns.c_str() , query , BSONObj() );
|
||||
scoped_ptr<ClientCursor> cc (new ClientCursor(QueryOption_NoCursorTimeout, cursor, ns));
|
||||
|
||||
while ( cursor->ok() ){
|
||||
if ( !cursor->matcher() || cursor->matcher()->matchesCurrent( cursor.get() ) ){
|
||||
BSONObj o = cursor->current();
|
||||
o.getFieldsDotted( key, values );
|
||||
}
|
||||
|
||||
cursor->advance();
|
||||
|
||||
if (!cc->yieldSometimes())
|
||||
break;
|
||||
|
||||
RARELY killCurrentOp.checkForInterrupt();
|
||||
}
|
||||
|
||||
BSONArrayBuilder b( result.subarrayStart( "values" ) );
|
||||
for ( BSONElementSet::iterator i = values.begin() ; i != values.end(); i++ ){
|
||||
b.append( *i );
|
||||
}
|
||||
BSONObj arr = b.done();
|
||||
|
||||
uassert(10044, "distinct too big, 4mb cap",
|
||||
(arr.objsize() + 1024) < (4 * 1024 * 1024));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} distinctCmd;
|
||||
|
||||
/* Find and Modify an object returning either the old (default) or new value*/
|
||||
class CmdFindAndModify : public Command {
|
||||
public:
|
||||
|
Loading…
Reference in New Issue
Block a user