Last active
August 29, 2015 14:03
-
-
Save mpobrien/d214d67b44548328bf3e to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Dump a cursor to BSON, from inside shell | |
// db.users.find({"username":"ian"}).dump("/tmp/users.bson") | |
// cursor options work: skip(), limit(), readpref, etc. | |
// Restore a collection from BSON, inside shell | |
// db.users.restore("/tmp/users.bson") | |
// You can dump aggregation data too | |
// db.users.aggregate({$group:{_id:"location", count:{$sum:1}}}).dump('/tmp/users_by_loc.bson') | |
diff --git a/src/mongo/scripting/v8_db.cpp b/src/mongo/scripting/v8_db.cpp | |
index 3a380ed..002866a 100644 | |
--- a/src/mongo/scripting/v8_db.cpp | |
+++ b/src/mongo/scripting/v8_db.cpp | |
@@ -32,6 +32,7 @@ | |
#include <iostream> | |
#include <iomanip> | |
#include <boost/scoped_array.hpp> | |
+#include <boost/filesystem/operations.hpp> | |
#include "mongo/base/init.h" | |
#include "mongo/client/sasl_client_authenticate.h" | |
@@ -92,6 +93,8 @@ namespace mongo { | |
ic->InstanceTemplate()->SetInternalFieldCount(1); | |
v8::Handle<v8::ObjectTemplate> icproto = ic->PrototypeTemplate(); | |
scope->injectV8Method("next", internalCursorNext, icproto); | |
+ scope->injectV8Method("dump", internalCursorDump, icproto); | |
+ | |
scope->injectV8Method("hasNext", internalCursorHasNext, icproto); | |
scope->injectV8Method("objsLeftInBatch", internalCursorObjsLeftInBatch, icproto); | |
scope->injectV8Method("readOnly", internalCursorReadOnly, icproto); | |
@@ -108,6 +111,7 @@ namespace mongo { | |
v8::Handle<v8::ObjectTemplate> proto = mongo->PrototypeTemplate(); | |
scope->injectV8Method("find", mongoFind, proto); | |
scope->injectV8Method("insert", mongoInsert, proto); | |
+ scope->injectV8Method("restore", mongoRestore, proto); | |
scope->injectV8Method("remove", mongoRemove, proto); | |
scope->injectV8Method("update", mongoUpdate, proto); | |
scope->injectV8Method("auth", mongoAuth, proto); | |
@@ -249,6 +253,82 @@ namespace mongo { | |
return c; | |
} | |
+ v8::Handle<v8::Value> mongoRestore(V8Scope* scope, const v8::Arguments& args) { | |
+ //argumentCheck(args.Length() == 3 ,"insert needs 3 args") | |
+ //argumentCheck(args[1]->IsObject() ,"attempted to insert a non-object") | |
+ | |
+ verify(scope->MongoFT()->HasInstance(args.This())); | |
+ | |
+ if (args.This()->Get(scope->v8StringData("readOnly"))->BooleanValue()) { | |
+ return v8AssertionException("js db in read only mode"); | |
+ } | |
+ | |
+ boost::shared_ptr<DBClientBase> conn = getConnection(scope, args); | |
+ const string ns = toSTLString(args[0]); | |
+ | |
+ v8::Handle<v8::Integer> flags = args[2]->ToInteger(); | |
+ | |
+ char filename[255]; | |
+ | |
+ args[1]->ToString()->WriteAscii(filename); | |
+ cout << "restoring from " << filename << endl; | |
+ | |
+ unsigned long long fileLength = boost::filesystem3::file_size(filename); | |
+ | |
+ FILE* _in = fopen(filename, "r"); | |
+ if (_in == NULL ){ | |
+ return v8AssertionException("failed to open input file"); | |
+ } | |
+ unsigned long long read = 0; | |
+ const int BUF_SIZE = BSONObjMaxUserSize + ( 1024 * 1024 ); | |
+ boost::scoped_array<char> buf_holder(new char[BUF_SIZE]); | |
+ char * buf = buf_holder.get(); | |
+ while ( read < fileLength ) { | |
+ size_t amt = fread(buf, 1, 4, _in); | |
+ if(amt != 4){ | |
+ break; | |
+ } | |
+ int size = ((int*)buf)[0]; | |
+ amt = fread(buf+4, 1, size-4, _in); | |
+ BSONObj o( buf ); | |
+ conn->insert(ns, o, flags->Int32Value()); | |
+ } | |
+ fclose(_in); | |
+ | |
+ /* | |
+ if(args[1]->IsArray()){ | |
+ v8::Local<v8::Array> arr = v8::Array::Cast(*args[1]); | |
+ vector<BSONObj> bos; | |
+ uint32_t len = arr->Length(); | |
+ argumentCheck(len > 0, "attempted to insert an empty array") | |
+ | |
+ for(uint32_t i = 0; i < len; i++){ | |
+ v8::Local<v8::Object> el = arr->CloneElementAt(i); | |
+ argumentCheck(!el.IsEmpty(), "attempted to insert an array of non-object types") | |
+ | |
+ // Set ID on the element if necessary | |
+ if (!el->Has(scope->v8StringData("_id"))) { | |
+ v8::Handle<v8::Value> argv[1]; | |
+ el->ForceSet(scope->v8StringData("_id"), | |
+ scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv)); | |
+ } | |
+ bos.push_back(scope->v8ToMongo(el)); | |
+ } | |
+ conn->insert(ns, bos, flags->Int32Value()); | |
+ } | |
+ else { | |
+ v8::Handle<v8::Object> in = args[1]->ToObject(); | |
+ if (!in->Has(scope->v8StringData("_id"))) { | |
+ v8::Handle<v8::Value> argv[1]; | |
+ in->ForceSet(scope->v8StringData("_id"), | |
+ scope->ObjectIdFT()->GetFunction()->NewInstance(0, argv)); | |
+ } | |
+ BSONObj o = scope->v8ToMongo(in); | |
+ conn->insert(ns, o); | |
+ }*/ | |
+ return v8::Undefined(); | |
+ } | |
+ | |
v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args) { | |
argumentCheck(args.Length() == 3 ,"insert needs 3 args") | |
argumentCheck(args[1]->IsObject() ,"attempted to insert a non-object") | |
@@ -415,6 +495,41 @@ namespace mongo { | |
} | |
/** | |
+ * cursor.dump() | |
+ */ | |
+ v8::Handle<v8::Value> internalCursorDump(V8Scope* scope, const v8::Arguments& args) { | |
+ mongo::DBClientCursor* cursor = getCursor(scope, args); | |
+ if (! cursor) | |
+ return v8::Undefined(); | |
+ | |
+ char filename[255]; | |
+ | |
+ args[0]->ToString()->WriteAscii(filename); | |
+ | |
+ FILE* _out = fopen(filename, "wb"); | |
+ if(_out == NULL){ | |
+ return v8AssertionException("failed to open output file"); | |
+ } | |
+ | |
+ while(cursor->more()){ | |
+ BSONObj o = cursor->next(); | |
+ | |
+ size_t toWrite = o.objsize(); | |
+ size_t written = 0; | |
+ | |
+ while (toWrite) { | |
+ size_t ret = fwrite( o.objdata()+written, 1, toWrite, _out ); | |
+ uassert(188893, errnoWithPrefix("couldn't write to file"), ret); | |
+ toWrite -= ret; | |
+ written += ret; | |
+ } | |
+ | |
+ } | |
+ fclose(_out); | |
+ return v8::Boolean::New(true); | |
+ } | |
+ | |
+ /** | |
* cursor.hasNext() | |
*/ | |
v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args) { | |
diff --git a/src/mongo/scripting/v8_db.h b/src/mongo/scripting/v8_db.h | |
index 5e9d02f..5d4bf0e 100644 | |
--- a/src/mongo/scripting/v8_db.h | |
+++ b/src/mongo/scripting/v8_db.h | |
@@ -54,6 +54,7 @@ namespace mongo { | |
// Mongo member functions | |
v8::Handle<v8::Value> mongoFind(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> mongoInsert(V8Scope* scope, const v8::Arguments& args); | |
+ v8::Handle<v8::Value> mongoRestore(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> mongoRemove(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> mongoUpdate(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> mongoAuth(V8Scope* scope, const v8::Arguments& args); | |
@@ -62,6 +63,7 @@ namespace mongo { | |
// Cursor object | |
v8::Handle<v8::Value> internalCursorCons(V8Scope* scope, const v8::Arguments& args); | |
+ v8::Handle<v8::Value> internalCursorDump(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> internalCursorNext(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> internalCursorHasNext(V8Scope* scope, const v8::Arguments& args); | |
v8::Handle<v8::Value> internalCursorObjsLeftInBatch(V8Scope* scope, const v8::Arguments& args); | |
diff --git a/src/mongo/shell/collection.js b/src/mongo/shell/collection.js | |
index 50ca2b8..7757a18 100644 | |
--- a/src/mongo/shell/collection.js | |
+++ b/src/mongo/shell/collection.js | |
@@ -191,6 +191,11 @@ DBCollection.prototype.findOne = function( query , fields, options ){ | |
return ret; | |
} | |
+DBCollection.prototype.restore = function( filename , options){ | |
+ var flags = 0; | |
+ this.getMongo().restore( this._fullName , filename, flags ); | |
+} | |
+ | |
DBCollection.prototype.insert = function( obj , options, _allow_dot ){ | |
if ( ! obj ) | |
throw Error( "no object passed to insert!" ); | |
@@ -1129,6 +1134,7 @@ DBCollection.prototype.aggregate = function(pipeline, extraOpts) { | |
if (!('cursor' in cmd)) { | |
// implicitly use cursors | |
cmd.cursor = {}; | |
+ cmd.cursor.batchSize = 0; | |
} | |
var res = this.runCommand("aggregate", cmd); | |
@@ -1151,8 +1157,9 @@ DBCollection.prototype.aggregate = function(pipeline, extraOpts) { | |
assert.commandWorked(res, "aggregate failed"); | |
- if ("cursor" in res) | |
- return new DBCommandCursor(this._mongo, res); | |
+ if ("cursor" in res){ | |
+ return new DBCommandCursor(this._mongo, res); | |
+ } | |
return res; | |
} | |
diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js | |
index a28e3b2..af9af69 100644 | |
--- a/src/mongo/shell/mongo.js | |
+++ b/src/mongo/shell/mongo.js | |
@@ -15,6 +15,8 @@ if ( ! Mongo.prototype.find ) | |
Mongo.prototype.find = function( ns , query , fields , limit , skip , batchSize , options ){ throw Error("find not implemented"); } | |
if ( ! Mongo.prototype.insert ) | |
Mongo.prototype.insert = function( ns , obj ){ throw Error("insert not implemented"); } | |
+if ( ! Mongo.prototype.restore ) | |
+ Mongo.prototype.restore = function( ns , obj ){ throw Error("insert not implemented"); } | |
if ( ! Mongo.prototype.remove ) | |
Mongo.prototype.remove = function( ns , pattern ){ throw Error("remove not implemented"); } | |
if ( ! Mongo.prototype.update ) | |
diff --git a/src/mongo/shell/query.js b/src/mongo/shell/query.js | |
index 304a96c..c2ed288 100644 | |
--- a/src/mongo/shell/query.js | |
+++ b/src/mongo/shell/query.js | |
@@ -110,6 +110,13 @@ DBQuery.prototype.skip = function( skip ){ | |
return this; | |
} | |
+DBQuery.prototype.dump = function(outfile){ | |
+ this._exec(); | |
+ | |
+ var o = this._cursor.dump(outfile); | |
+ return o; | |
+} | |
+ | |
DBQuery.prototype.hasNext = function(){ | |
this._exec(); | |
@@ -420,6 +427,9 @@ DBCommandCursor.prototype.next = function() { | |
return ret; | |
} | |
} | |
+DBCommandCursor.prototype.dump = function(filename) { | |
+ return this._cursor.dump(filename); | |
+} | |
DBCommandCursor.prototype.objsLeftInBatch = function() { | |
if (this._firstBatch.length) { | |
return this._firstBatch.length; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment