stijnsanders / TMongoWire

Delphi MongoDB driver
MIT License
102 stars 37 forks source link

How execute mongodb function (JavaScript) from Delphi #20

Closed CapDev12 closed 10 years ago

CapDev12 commented 10 years ago

i write in mongo.exe console any function :

var func1=function (str) {return db.Stats.find({idPl:{$in:db.Players.distinct('_id',{PN: str})}})}

How call this function from Delphi

FMongoWire.Get('mongodb_test.func1(/qwe/)', nil); //Not work !

stijnsanders commented 10 years ago

distinct is apparently an internal command, please try this (I'm not sure about the 'db.' in 'db.Stats', in the past I've seen the mongo server require a prefix, but it may need to be the server name)

FMongoWire.Get('db.Stats',BSON(['idPL','[','$in', FMongoWire.Get('db.$command',BSON(['distinct','Players','key','_id','query','[','PN','str',']'])), ']']));

CapDev12 commented 10 years ago

Error: 'MongoWire.Get: no documents returned'

How to call any other command (except. insert (). find (). save ()) for example

db.Stats.distinct ('S0') [70.83, 99.14, 47.67, 39.64, 76.03, 74.22]

or

db.Stats.mapReduce(...,...)

mongo-delphi-driver have function

       function command (db: string; command: TBson): TBson; overload;        {Issue a command to the server. This version of the command () function          supports that subset of commands which may be described by a cmdstr and          an argument.          If successful, the response from the server is returned as a TBson document;          otherwise, nil is returned.          See http://www.mongodb.org/display/DOCS/List+of+Database+Commands}

       function command (db: string; cmdstr: string; arg: OleVariant): TBson; overload;        {Get the last error reported by the server. Returns a TBson document describing          the error if there was one; otherwise, nil. }

maybe this is what you need

TMongoWire has a similar ?

stijnsanders commented 10 years ago

TMongoWire is a 'raw' connector built from scratch, not really a 'full' driver with all the features a driver should have. MongoDB commands are actually requests against the "$command" collection. MapReduce could look something like this:

FMongoWire.Get('db.$command',BSON([
  'mapreduce','db.MyCollection',
  'map',bsonJavaScriptCodePrefix+'function(...',
  'reduce,bsonJavaScriptCodePrefix+'function(...',
  //etc. see http://docs.mongodb.org/manual/reference/command/mapReduce/
]));
stijnsanders commented 10 years ago

I have read your question once more (...), and what you're asking is probably more in the line of this: http://docs.mongodb.org/manual/tutorial/store-javascript-function-on-server/ combined with the things from above, try this:

FMongoWire.Insert('system.js',BSON(['_id','func1','value',bsonJavaScriptCodePrefix+'function(...']));

then, using http://docs.mongodb.org/manual/reference/command/eval/#dbcmd.eval

FMongoWire.Insert('db.command$',BSON(['eval','func1','args',VarArrayOf([...])]));

or (if I understand the docs correctly) this should work as well:

FMongoWire.Insert('db.command$',BSON(['eval',bsonJavaScriptCodePrefix+'function(...','args',VarArrayOf([...])]));
CapDev12 commented 10 years ago

This method http://docs.mongodb.org/manual/tutorial/store-javascript-function-on-server/ very usefull. Very thanks for this ! It works.

//Simple function // db.system.js.save( { _id:"echo200", value : function() { return {Hello: 200}}})

FMongoWire.Insert('mongodb_test.system.js', BSON(['_id','echo200', 'value', 'function() { return {Hello: 200}}'])); //work

But Exec not work ! FMongoWire.Insert('db.command$',BSON(['eval','func1','args',VarArrayOf([...])])); //not work

FMongoWire.Insert('mongodb_test.command$', BSON(['eval','echo200'])); //not work FMongoWire.Insert('db.command$', BSON(['eval','echo200'])); //not work

How it could work if it Insert ??!! Inside function Insert - translate in "db.coll.save()" And where the result is returned ?

FMongoWire.Get('db.command$', BSON(['eval','echo200'])); //not work, the same Get - translate in "db.coll.find()"

Please, you could : send this in your mongodb

db.system.js.save( { _id:"echo200", value : function() { return {Hello: 200}}}) db.loadServerScripts()

and try Exec this function from the Delphi

and public this sample here Would be very grateful !

stijnsanders commented 10 years ago

This works for me (my server's internal name is "test")

var
  d:IBSONDocument;
begin
  FMongoWire.Insert('test.system.js',BSON(['_id','x1','value',bsonJavaScriptCodePrefix+
    'function(){return {test:123};}'
    ]));
  d:=FMongoWire.Get('test.$cmd',BSON(['eval','x1();']));
  Memo1.Text:=BsonToJson(IUnknown(d['retval']) as IBSONDocument);
end;
stijnsanders commented 10 years ago

Apparently it's "$cmd" not "command$" I had to check the shell source again to be sure: https://github.com/mongodb/mongo/blob/master/src/mongo/shell/db.js#L53

CapDev12 commented 10 years ago

I at last compiled mongo-delphi-driver ... Visual Studio had to install

Run js comannd work

b:= mongo.command(db, BSON(['eval','echo200()']));
b='retval: Hello: 200 ok: 1 '

Thanks for 'eval' hint !

CapDev12 commented 10 years ago

You also works too cool !

means that there are two good drivers

thanks for sample