Skip to content

Instantly share code, notes, and snippets.

@mpobrien
Last active August 29, 2015 14:03
Show Gist options
  • Save mpobrien/d214d67b44548328bf3e to your computer and use it in GitHub Desktop.
Save mpobrien/d214d67b44548328bf3e to your computer and use it in GitHub Desktop.
// 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