blah;
while ( cursor->more() ){
BSONObj obj = cursor->next();
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 char *dbname, BSONObj& jsobj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
static DBDirectClient db;
/* db.$cmd.findOne( { group : } ) */
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 );
string ns = dbname;
ns = ns.substr( 0 , ns.size() - 4 );
string realdbname = ns.substr( 0 , ns.size() - 1 );
if ( p["ns"].type() != String ){
errmsg = "ns has to be set";
return false;
}
ns += p["ns"].valuestr();
auto_ptr cursor = db.query( ns , q );
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( realdbname , cursor ,
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() { return true; }
virtual void help( stringstream &help ) const {
help << "{ distinct : 'collection name' , key : 'a.b' }";
}
bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool fromRepl ){
static DBDirectClient db;
string ns = cc().database()->name + '.' + cmdObj.getField(name).valuestr();
string key = cmdObj["key"].valuestrsafe();
BSONObj keyPattern = BSON( key << 1 );
set map;
long long size = 0;
auto_ptr cursor = db.query( ns , getQuery( cmdObj ) , 0 , 0 , &keyPattern );
while ( cursor->more() ){
BSONObj o = cursor->next();
BSONObj value = o.extractFields( keyPattern );
if ( value.isEmpty() )
continue;
if ( map.insert( value ).second ){
size += o.objsize() + 20;
uassert( 10044 , "distinct too big, 4mb cap" , size < 4 * 1024 * 1024 );
}
}
assert( size <= 0x7fffffff );
BSONObjBuilder b( (int) size );
int n=0;
for ( set::iterator i = map.begin() ; i != map.end(); i++ ){
b.appendAs( i->firstElement() , b.numStr( n++ ).c_str() );
}
result.appendArray( "values" , b.obj() );
return true;
}
} distinctCmd;
/* Find and Modify an object returning either the old (default) or new value*/
class CmdFindAndModify : public Command {
public:
/* {findandmodify: "collection", query: {processed:false}, update: {$set: {processed:true}}, new: true}
* {findandmodify: "collection", query: {processed:false}, remove: true, sort: {priority:-1}}
*
* either update or remove is required, all other fields have default values
* output is in the "value" field
*/
CmdFindAndModify() : Command("findandmodify") { }
virtual bool logTheOp() {
return false; // the modification will be logged directly
}
virtual bool slaveOk() {
return false;
}
virtual bool run(const char *dbname, BSONObj& cmdObj, string& errmsg, BSONObjBuilder& result, bool) {
static DBDirectClient db;
string ns = nsToDatabase(dbname) + '.' + cmdObj.firstElement().valuestr();
Query q (cmdObj.getObjectField("query")); // defaults to {}
BSONElement sort = cmdObj["sort"];
if (!sort.eoo())
q.sort(sort.embeddedObjectUserCheck());
BSONObj out = db.findOne(ns, q);
if (out.firstElement().eoo()){
errmsg = "No matching object found";
return false;
}
q = QUERY( "_id" << out["_id"]);
if (cmdObj["remove"].trueValue()){
uassert(12515, "can't remove and update", cmdObj["update"].eoo());
db.remove(ns, q, 1);
} else {
BSONElement update = cmdObj["update"];
uassert(12516, "must specify remove or update", !update.eoo());
db.update(ns, q, update.embeddedObjectUserCheck());
if (cmdObj["new"].trueValue())
out = db.findOne(ns, q);
}
result.append("value", out);
return true;
}
} cmdFindAndModify;
bool commandIsReadOnly(BSONObj& _cmdobj) {
BSONObj jsobj;
{
BSONElement e = _cmdobj.firstElement();
if ( e.type() == Object && string("query") == e.fieldName() ) {
jsobj = e.embeddedObject();
}
else {
jsobj = _cmdobj;
}
}
BSONElement e = jsobj.firstElement();
if ( ! e.type() )
return false;
return Command::readOnly( e.fieldName() );
}
/* TODO make these all command objects -- legacy stuff here
usage:
abc.$cmd.findOne( { ismaster:1 } );
returns true if ran a cmd
*/
bool _runCommands(const char *ns, BSONObj& _cmdobj, BufBuilder &b, BSONObjBuilder& anObjBuilder, bool fromRepl, int queryOptions) {
string dbname = nsToDatabase( ns );
if( logLevel >= 1 )
log() << "run command " << ns << ' ' << _cmdobj << endl;
const char *p = strchr(ns, '.');
if ( !p ) return false;
if ( strcmp(p, ".$cmd") != 0 ) return false;
BSONObj jsobj;
{
BSONElement e = _cmdobj.firstElement();
if ( e.type() == Object && string("query") == e.fieldName() ) {
jsobj = e.embeddedObject();
}
else {
jsobj = _cmdobj;
}
}
Client& client = cc();
bool ok = false;
BSONElement e = jsobj.firstElement();
Command * c = e.type() ? Command::findCommand( e.fieldName() ) : 0;
if ( c ){
string errmsg;
AuthenticationInfo *ai = client.getAuthenticationInfo();
bool needWriteLock = ! c->readOnly();
if ( ! c->requiresAuth() &&
( ai->isAuthorizedReads( dbname ) &&
! ai->isAuthorized( dbname ) ) ){
// this means that they can read, but not write
// so only get a read lock
needWriteLock = false;
}
mongolock lk( needWriteLock );
Client::Context ctx( ns , dbpath , &lk , c->requiresAuth() );
bool admin = c->adminOnly();
if( admin && c->localHostOnlyIfNoAuth(jsobj) && noauth && !ai->isLocalHost ) {
ok = false;
errmsg = "unauthorized: this command must run from localhost when running db without auth";
log() << "command denied: " << jsobj.toString() << endl;
}
else if ( admin && !fromRepl && strncmp(ns, "admin", 5) != 0 ) {
ok = false;
errmsg = "access denied";
log() << "command denied: " << jsobj.toString() << endl;
}
else if ( isMaster() ||
c->slaveOk() ||
( c->slaveOverrideOk() && ( queryOptions & QueryOption_SlaveOk ) ) ||
fromRepl ){
if ( jsobj.getBoolField( "help" ) ) {
stringstream help;
help << "help for: " << e.fieldName() << " ";
c->help( help );
anObjBuilder.append( "help" , help.str() );
}
else {
if( admin )
log( 2 ) << "command: " << jsobj << endl;
try {
ok = c->run(ns, jsobj, errmsg, anObjBuilder, fromRepl);
}
catch ( AssertionException& e ){
ok = false;
errmsg = "assertion: ";
errmsg += e.what();
}
if ( ok && c->logTheOp() && !fromRepl )
logOp("c", ns, jsobj);
}
}
else {
ok = false;
errmsg = "not master";
}
if ( !ok )
anObjBuilder.append("errmsg", errmsg);
}
else {
anObjBuilder.append("errmsg", "no such cmd");
anObjBuilder.append("bad cmd" , _cmdobj );
}
anObjBuilder.append("ok", ok?1.0:0.0);
BSONObj x = anObjBuilder.done();
b.append((void*) x.objdata(), x.objsize());
return true;
}
} // namespace mongo