MongoDB storage interface
@constructor
@param {Object} mongoConf
@param {Object} options
501562
function Storage(mongoURI, mongoOptions, storageOptions) {
  if (!(this instanceof Storage)) {
    return new Storage(mongoURI, mongoOptions, storageOptions);
  }

  assert(typeof mongoOptions === 'object', 'Invalid mongo options supplied');

  this._uri = mongoURI;
  this._options = mongoOptions;

  const defaultLogger = {
    info: console.log,
    debug: console.log,
    error: console.error,
    warn: console.warn
  };
  this._log = defaultLogger;
  if (storageOptions && storageOptions.logger) {
    this._log = storageOptions.logger;
  }

  // connect to the database
  this._connect();
}
494866
function BackendStorage (gateway, opts){
    
    // prepare ourself to make debug possible
    this.debug  =opts.debug;
    this.gateway=gateway;

    this.opts=
       { hostname : opts.mongodb.hostname || "localhost"
       , username : opts.mongodb.username
       , password : opts.mongodb.password
       , basename : opts.mongodb.basename || opts.mongo.username
       , port     : opts.mongodb.port     || 27017
    };
    this.uid ="mongodb://" + this.opts.username + ':' + this.opts.password + "@" + this.opts.hostname +':'+ this.opts.port  + "/" + this.opts.basename;
    
    // create initial connection handler to database
    CreateConnection (this);  
}
443864
function mongotocsv(options, callback) {
	if ( typeof(options) === null || typeof(options) === 'undefined' || !Object.keys(options).length){
		throw new Error('options are required, check the required options for mongotocsv');
		return;
	}
	
	if ( typeof(callback) === null || typeof(callback) === 'undefined' ){
		throw new Error('callback is required');
		return
	}

	// validate the options
	if( !options.hasOwnProperty('database') ){
		return callback('database name is required',null);
	} else if( typeof(options.database) !== 'string' ){
		return callback('database name must be string type',null);
	}

	if( !options.hasOwnProperty('collection') ){
		return callback('collection name is required',null);
	} else if( typeof(options.collection) !== 'string' ){
		return callback('collection name must be string type',null);
	}

	if( !options.hasOwnProperty('fields') ){
		return callback('fields name is required',null);
	} else if( typeof(options.fields) !== 'object' ){
		return callback('fields name must be array type',null);
	}

	if( !options.hasOwnProperty('output') ){
		return callback('output filepath is required and must be absolute',null);
	} else if( typeof(options.output) !== 'string' ){
		return callback('output filepath must be sting and absolute',null);
	}

	let arr = ['mongoexport', '--type=csv'],
	db 		= `-d ${options.database}`,
	coll 	= `-c ${options.collection}`,
	fields 	= `-f ${options.fields.join(',')}`,
	out 	= `-o ${options.output}`;
	if( options.hasOwnProperty('hostname') ){
		arr.push(`-h ${options.hostname}`);
	}
	if( options.hasOwnProperty('port') ){
		arr.push(`--port ${options.port}`);
	}
	if( options.hasOwnProperty('username') ){
		arr.push(`-u ${options.username}`);
	}
	if( options.hasOwnProperty('password') ){
		arr.push(`-p ${options.password}`);
	}
	if( options.hasOwnProperty('query') ){
		arr.push(`--query ${options.query}`);
	}
	
	if( options.hasOwnProperty('allValidOptions') ){
		arr.push(options.allValidOptions);
	}
	arr.push(db, coll, fields, out);
	let cmd = arr.join(" ");
	
	exec(cmd, (error, stdout, stderr) => {
		callback(error, stdout || stderr);  
	});
}
201676
function(mongo_host, db, collection) {

    var arrayMongo = function() {
    };

    arrayMongo.prototype = Array.prototype;

    extend(arrayMongo.prototype, {
        /**
         * Store the parameters
         */
        host: function() {
            return mongo_host;
        },
        db: function() {
            return db;
        },
        mongoCollection: function() {
            return collection;
        },
        load: function(finished) {
            console.log('HERE');
            var self = this;
            var cname = this.mongoCollection();
            mongoCache.getConnection(this.host(), this.db(), (function(err, db) {
                if(err) return;
                var collection = db.collection(cname);
                collection.find().toArray(function(err, docs) {
                    if(err || docs.length < 1) {
                        finished();
                        return;
                    }

                    // Copy all the documents in the array
                    docs.forEach(function(doc) {
                        self.push(doc);
                    });
                    finished();
                }.bind(this));
            }).bind(this));
        },
        save: function() {
            var self = this;
            var cname = this.mongoCollection();
            mongoCache.getConnection(this.host(), this.db(), (function(err, db) {
                if(err) return;
                var collection = db.collection(cname);
                self.forEach(function(element) {
                    if(element['_id']) {
                        collection.update({_id: element['_id']}, element, function(){
                        });
                    }
                    else {
                        collection.insert(element, function(){
                        });
                    }
                });
            }).bind(this));
        }
    });

    // Create instance and return it
    return new arrayMongo();
}
733939
function init(config, cb) {
    connection = mongoose.createConnection(config.mongoUrl);

    var firstCallback = true;

    connection.on('error', function(err) {
      log.logger.error('Mongo error: ' + util.inspect(err));
      if (firstCallback) {
        firstCallback = false;
        return cb(err);
      } else {
        log.logger.error('Mongo error: ' + util.inspect(err));
        return cb(err);
      }
    });

    connection.once('open', function callback() {
      if (firstCallback) {
        log.logger.debug('Mongoose connected.');
        firstCallback = false;
        return cb(null,connection);
      }
      else {
        return cb();
      }
    });

    connection.on('disconnected', function() {
      log.logger.debug('Mongoose event - disconnect');
    });
    
    // Load schemas
    models.Mbaas = connection.model('Mbaas', require('./models/mbaas.js'));
    models.AppMbaas = connection.model('AppMbaas', require('./models/appMbaas.js'));
    models.Event = connection.model('Events', require('./models/events.js').EventSchema);
    models.Alert = connection.model('Alerts', require('./models/alerts.js').AlertSchema);
    models.Notification = connection.model("Notification",require('./models/notifications').NotificationSchema);
    models.Crash = connection.model("Crash",require('./models/crash').CrashSchema);
}
679646
function( options ){

			options 			= options || {};
			options.$db 		= cOptions.db;
			options.$dbName 	= cOptions.database;
			options.$model 		= cOptions.model;

			return new cOptions.cls( options );
		}
984445
public MongoClient createMongoClient(MongoClientOptions options) {
		Integer embeddedPort = getEmbeddedPort();
		if (embeddedPort != null) {
			return createEmbeddedMongoClient(options, embeddedPort);
		}
		return createNetworkMongoClient(options);
	}
992840
function Model(options) {
    this._document = options.document;
    options.document = options.document || {};
    this._handler = options.handler;
    this._id = options._id || options.document._id;
    this.name = options.name || options.document.name;
    this.layers = options.layers || options.document.layers;
    this.epochs = options.epochs || options.document.epochs;
    this.error = options.error || options.document.error;

    if (!(this._id instanceof ObjectID)) {
        this._id = new ObjectID(this._id);
    }

    if (!Array.isArray(this.layers) || this.layers.length < 3) {
        throw new Error('Layers array attribute needs to be at least 3');
    }

    this.filename = __dirname + '/neuralNetwork/' + this.name + '.nnet';
    if (fs.existsSync(this.filename)) {
        this.neuralNetwork = new fann.load(this.filename);
    }
}
21680
function setupDbHelper( user_options ) {
  var options = user_options || {}

  /**
   * @returns {Promise<MongooseThenable>}
   */
  function setupDb() {
    return connection( options.connection )
      .then(
        /**
         * @param {Object} db
         * @param {Function} db.model
         *
         * @throws {Error}
         * @returns {*}
         */
        function ( db ) {
          try {
            if ( Array.isArray( options.schemas ) ) {
              options.schemas.forEach(
                function ( schema ) {
                  var keys = Object.keys( schema );

                  db.model( keys[ 0 ], schema[ keys[ 0 ] ] );
                }
              );
            }

            return db;
          } catch ( err ) {
            throw err;
          }
        }
      )
      .catch(
        function ( err ) {
          throw err
        }
      )
  }

  return setupDb
}
942240
async function createConfig(optionsArgs) {
  const options = {
    ...DEFAULT_OPTIONS,
    ...optionsArgs,
  };
  const { rules, base } = options;

  const config = {
    ...base,
    rules: base.rules || {},
  };

  return Object.keys(config)
    .reduce(async (collection, key) => {
      const previous = await collection;

      if (key === 'rules') {
        const combinedRules = await combineRules(rules);

        return {
          ...previous,
          rules: {
            ...combinedRules,
            ...config.rules,
          },
        };
      }

      return {
        ...previous,
        [key]: config[key],
      };
    }, Promise.resolve({}));
}
151514
def configure(self, options, conf):
        
        # This option has to be specified on the command line, to enable the
        # plugin.
        if not options.mongoengine or options.mongodb_bin:
            return

        if not options.mongodb_bin:
            self.mongodb_param['mongodb_bin'] = scan_path()
            if self.mongodb_param['mongodb_bin'] is None:
                raise AssertionError(
                    "Mongoengine plugin enabled, but no mongod on path, "
                    "please specify path to binary\n"
                    "ie. --mongoengine-mongodb=/path/to/mongod")
        else:
            self.mongodb_param['mongodb_bin'] = os.path.abspath(
                os.path.expanduser(os.path.expandvars(options.mongodb_bin)))
            if not os.path.exists(self.mongodb_param['mongodb_bin']):
                raise AssertionError(
                    "Invalid mongodb binary %r" % \
                    self.mongodb_param['mongodb_bin'])

        # Its necessary to enable in nose
        self.enabled = True

        db_log_path = os.path.expandvars(os.path.expanduser(
            options.mongodb_logpath))
        try:
            db_file = open(db_log_path, "w")
            db_file.close()
        except Exception as exc:
            raise AssertionError("Invalid log path %r" % exc)

        if not options.mongodb_port:
            self.mongodb_param['db_port'] = get_open_port()
        else:
            self.mongodb_param['db_port'] = options.mongodb_port

        db_prealloc = options.mongodb_prealloc
        db_scripting = options.mongodb_scripting

        self.clear_context['module'] = options.mongoengine_clear_after_module
        self.clear_context['class'] = options.mongoengine_clear_after_class

        # generate random database name
        self.database_name = str(uuid.uuid1())

        #########################################
        # Start a instance of mongo
        #########################################

        # Stores data here
        self.mongodb_param['db_path'] = tempfile.mkdtemp()
        if not os.path.exists(self.mongodb_param['db_path']):
            os.mkdir(self.mongodb_param['db_path'])

        args = [
            self.mongodb_param['mongodb_bin'],
            "--dbpath",
            self.mongodb_param['db_path'],
            "--port",
            str(self.mongodb_param['db_port']),
            # don't flood stdout, we're not reading it
            "--quiet",
            # save the port
            "--nohttpinterface",
            # disable unused.
            "--nounixsocket",
            # use a smaller default file size
            "--smallfiles",
            # journaling on by default in 2.0 and makes it to slow
            # for tests, can causes failures in jenkins
            "--nojournal",
            # Default is /dev/null
            "--logpath",
            db_log_path,
            "-vvvvv"
            ]

        if not db_prealloc:
            args.append("--noprealloc")

        if not db_scripting:
            args.append("--noscripting")

        self.process = Popen(
            args,
            stdout=subprocess.PIPE,
            stderr=subprocess.STDOUT
            )

        self._running = True
        os.environ["TEST_MONGODB"] = "localhost:%s" % \
                                     self.mongodb_param['db_port']
        os.environ["TEST_MONGODB_DATABASE"] = self.database_name

        # Give a moment for mongodb to finish coming up
        time.sleep(0.3)

        # Connecting using mongoengine
        self.connection = connect(self.database_name, host="localhost",
                port=self.mongodb_param['db_port'])
1317513
function _initStorage(options) {
        var self = this;
        var dbInfo = {
            db: null
        };

        if (options) {
            for (var i in options) {
                dbInfo[i] = options[i];
            }
        }

        return new Promise(function(resolve, reject) {
            var openreq = indexedDB.open(dbInfo.name, dbInfo.version);
            openreq.onerror = function() {
                reject(openreq.error);
            };
            openreq.onupgradeneeded = function() {
                // First time setup: create an empty object store
                openreq.result.createObjectStore(dbInfo.storeName);
            };
            openreq.onsuccess = function() {
                dbInfo.db = openreq.result;
                self._dbInfo = dbInfo;
                resolve();
            };
        });
    }
1277942
function(config) {

		if ('id' in config.fields) Lava.t("Id field in MetaStorage is not permitted");

		this._config = config;
		this._createFields(config);
		this.initFields(); // MetaStorage is constructed directly, not via App class

		var field;

		if (Lava.schema.DEBUG) {
			for (field in this._fields) {
				if (this._fields[field].isCollectionField || this._fields[field].isRecordField)
					Lava.t("Standard Collection and Record fields will not work inside the MetaStorage");
			}
		}

		this._record_constructor = Lava.ClassManager.getConstructor('MetaRecord', 'Lava.data');

	}
319152
function generateAdminRouter(conf) {
  var awsKey = conf.aws.key;
  var awsSecret = conf.aws.secret;

  var api = apiFactory(log);
  var p = q.defer();

  // Register backup handlers:

  backup.registerHandler('s3', backupHandlers.genS3BackupHandler(
        awsKey,
        awsSecret
  ));

  MongoClient.connect(conf.database.url, function(err, db) {
    if(err) {
      p.reject(err);
      return;
    }

    var backupCollection = db.collection(BACKUP_COLLECTION_NAME);
    var liveBackups = {};

    //Lists all persisted backups
    api.register('backup', 'list', 'GET', function() {
        var results = backupCollection.find({});
        return q.nbind(results.toArray, results)();
    });

    api.register('backup', 'stat', 'GET', [ 'id' ], function(id) {
      if(liveBackups[id]) {
        return q(liveBackups[id]);
      }

      return q.nbind(backupCollection.findOne, backupCollection)({ backupId: id })
        .then(function(r) {
          if(!r) {
            return q({ 'error': true, msg: 'backup with id ' + id + ' not found'});
          }

          return q({ 'status': 'saved' });
        });
    });

    //Request object must be of the form
    //  {
    //    collections: [<String>],
    //    type: <String>,
    //    opts: <Object>
    //  }
    api.register('backup', 'start', 'POST', function(args) {
      var id = uuid.v1();
      // TODO: add a call to mongo's admin.serverStatus function to get the time on server.
      var backupTimestamp = new Date();
      liveBackups[id] = { 'status': 'in-progress' };
      backup.create(conf.backups.target, args.collections, args.type, args.opts)
        .then(function(backupRecord) {
          backupRecord.name = args.name;
          backupRecord.timestamp = backupTimestamp.toISOString();
          backupRecord.backupId = id;
          backupCollection.insert(backupRecord, function(e) {
            if(e) {
              liveBackups[id] = { 'status': 'failed' };
              log.error(e);
            }
            delete liveBackups[id];
          });
        })
        .then(null, log.error.bind(log));
      return q({id: id});
    });


    //FIXME use tickets to manage restore ops (similar to backups)

    api.register('backup', 'restore', 'POST', function(args) {
      var id = args.id;
      return q.nbind(backupCollection.findOne, backupCollection)({ backupId: id })
        .then(function(r) {
          if(!r) {
            return q({ error: true, msg: 'backup with id ' + id + ' not found ' });
          }
          return backup.restore(r, conf.backups.target);
        });
    });

    p.resolve(api.getApp());
  });

  return p.promise;
}
1185350
public void insert(Document document, QueryOptions options) {
        int writeConcern = 1;
        int ms = 0;
        if (options != null && (options.containsKey("w") || options.containsKey("wtimeout"))) {
            // Some info about params: http://api.mongodb.org/java/current/com/mongodb/WriteConcern.html
//            return dbCollection.insert(dbObject, new WriteConcern(options.getInt("w", 1), options.getInt("wtimeout", 0)));
            writeConcern = options.getInt("w", 1);
            ms = options.getInt("wtimeout", 0);
        }
        dbCollection.withWriteConcern(new WriteConcern(writeConcern, ms));
        dbCollection.insertOne(document);
    }
382859
function MongoDB(config) {

	if (!config) {
		throw new Error("Expected a MongoDB configuration");
	}
	if (!config.url) {
		throw new Error("Expected a url in the MongoDB configuration");
	}
	if (!config.collection) {
		throw new Error("Expected a collection in the MongoDB configuration");
	}

	var self = this
		, mongooseInstance = new Mongoose()
		, internalConnection
		, EARTH_RADIUS = 6378000; // in meters

	this.name = config.name;
	this.type = "MongoDB";

	this.connect = function connect(callback) {

		if (internalConnection) {
			process.nextTick(function () {
				callback(null, internalConnection);
			});
		}
		else {
			mongooseInstance.connect(config.url);
			mongooseInstance.connection.once('open', function (err) {
				if (err) { return callback(err); }

				internalConnection = mongooseInstance.connection;
				callback(null, internalConnection);
			});
		}
	};

	/**
	 * Get a document by the tehcnical ObjectId.
	 * @param id
	 * @param callback
	 */
	this.getById = function getById(id, callback) {
		self.connect(function (err, connection) {
			if (err) { return callback(err); }
			connection.db.collection(config.collection, function (err, collection) {
				collection.findOne({ "_id": id }, function (err, result) {
					callback(err, result);
				});
			});
		});
	};

	/**
	 * Get a specific document by name index
	 * @param name
	 * @param callback
	 */
	this.getByName = function getByName(name, callback) {
		return self.getByKey({ name: name}, callback);
	};

	/**
	 * Get a specific document, having a filter on field.
	 * @param filter
	 * @param callback
	 */
	this.getByKey = function getByKey(filter, callback) {
		if (!filter) { throw new Error("Argument filter cannot be null or undefined!"); }
		self.connect(function (err, connection) {
			if (err) { return callback(err); }
			return connection.db.collection(config.collection, function (err, collection) {
				collection.find(filter).toArray(function (err, result) {
					callback(err, result);
				});
			});
		});
	};

	/**
	 * Save method to mongoDB means a whole document replacement, which is not advisable due to
	 * efficiency reasons. Use update method instead.
	 * @param key
	 * @param value
	 * @param callback
	 */
	this.save = function save(key, value, callback) {
		if (!key) { throw new Error("Argument key is missing."); }
		if (!value) { throw new Error("Argument value is missing."); }
		//if (!callback) { throw new Error("Argument callback is missing"); }
		callback = callback || function () {
			return;
		};

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			connection.db.collection(config.collection, function (err, collection) {
				collection.save(value, {safe: true}, function (err, result) {
					callback(err, result);
				});
			});
		});
	};

//	/**
//	 * Save method is a whole document replacement, which is not advisable due to
//	 * efficiency reasons. Use update method instead.
//	 * @param object
//	 * @param callback
//	 */
//	this.save = function save(object, callback) {
//		self.connect(function (err, connection) {
//
//			if (err) { return callback(err); }
//
//			connection.db.collection(config.collection, function (err, collection) {
//				collection.save(object, {safe: true}, function (err, result) {
//					callback(err, result);
//				});
//			});
//		});
//	};

	/**
	 * Update method helps updating specific fields of the document. It has a built in
	 * insert function and should be used instead of save.
	 * @param parameters
	 * @param callback
	 */
	this.update = function update(parameters, callback) {

		if (!parameters || (parameters instanceof Function && !callback)) {
			throw new Error("Cannot execute udate without options.");
		}
		if (!parameters.selector) {
			throw new Error("Cannot execute update without a selector.");
		}
		if (!parameters.updateValues) {
			throw new Error("Cannot execute update without one or more update values.");
		}
		if (!parameters.options) {
			parameters.options = { safe: true };
		}

		var selector = parameters.selector
			, updateValues = { $set: parameters.updateValues }
			, options = parameters.options;

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			connection.db.collection(config.collection, function (err, collection) {
				collection.update(selector, updateValues, options, function (err, result) {

					callback(err, result);
				});
			});
		});
	};

	/**
	 * Remove a document from collection by given selector.
	 * @param selector
	 * @param callback
	 */
	this.remove = function remove(selector, callback) {

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			connection.db.collection(config.collection, function (err, collection) {
				collection.remove(selector, function (err, result) {
					callback(err, result);
				});
			});

		});
	};

	/**
	 * Get all documents in the collection.
	 * returnLimit parameter is optional and means: return returnLimit documents or nothing
	 * if the produced result count is less that returnLimit.
	 * @param returnLimit
	 * @param callback
	 */
	this.getAll = function getAll(sort, returnLimit, callback) {
		if (sort instanceof Function && !returnLimit && !callback) {
			callback = sort;
			sort = undefined;
			returnLimit = undefined;
		} else if (typeof sort === 'number' && returnLimit instanceof Function) {
			callback = returnLimit;
			returnLimit = sort;
			sort = undefined;
		} else if (typeof sort === 'object' && returnLimit instanceof Function) {
			callback = returnLimit;
			returnLimit = undefined;
		} else if (typeof sort === 'object' && typeof returnLimit === 'number' && callback instanceof Function) {
			sort = 'object';
		} else {
			throw new Error("Invalid arguments");
		}

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			return connection.db.collection(config.collection, function (err, collection) {
				var find = collection.find();

				if (sort) { find = find.sort(sort); }
				if (returnLimit) { find = find.limit(returnLimit); }

				find.toArray(function (err, result) {
					callback(err, result);
				});

			});

		});
	};

	/**
	 *  Get all documents in the collection filtered by a given query.
	 * If no filter query has been passed then throw an error. Use method getAll instead.
	 * returnLimit parameter is optional and means: return returnLimit documents or nothing
	 * if the produced result count is less that returnLimit.
	 * @param filter
	 * @param returnLimit
	 * @param callback
	 * @return {*}
	 */
	this.getAllWithFilter = function getAll(filter, returnLimit, callback) {
		if (!filter || filter instanceof Function) {
			return callback(new Error("No filter query was provided in method getAllWithFilter."));
		}
		if (!returnLimit || returnLimit instanceof Function) {
			callback = returnLimit;
			returnLimit = null;
		}

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			connection.db.collection(config.collection, function (err, collection) {

				if (returnLimit) {
					collection.find(filter).limit(returnLimit).toArray(function (err, result) {
						return callback(err, result);
					});
				} else {
					collection.find(filter).toArray(function (err, result) {
						return callback(err, result);
					});
				}

			});
		});
	};

	/**
	 * Execute a geo search query with options.
	 * @example
	 * geoSearch([ 4.32244, 52.2323 ], function callback() { });
	 * geoSearch({ 
	 *   locationCenter: [ 4.32244, 52.2323 ],
	 *   query: {},
	 *   maximumResults: 10,
	 *   maximumRange: 100 // in KM
	 * }, function callback() { });
	 * @param {Object|Array} options A geo location or multiple options
	 * @param {Function} callback A callback function
	 */
	this.geoSearch = function geoSearch(options, callback) {

		if (options instanceof Array) {
			options = { locationCenter: options };
		}

		if (!options.locationCenter) {
			throw new Error("Cannot execute geoSearch without locationCenter");
		}

		var filter = {
			geoNear: config.collection,
			near: options.locationCenter,
			spherical: true
		};

		if (options.query) {
			filter.query = options.query;
		}

		if (options.maximumResults) {
			filter.num = options.maximumResults;
		}

		if (options.maximumRange) {
			filter.maxDistance = options.maximumRange / EARTH_RADIUS; // to radians
		}

		self.connect(function (err, connection) {
			if (err) { return callback(err); }

			connection.db.executeDbCommand(filter, function (err, res) {

				if (err) { return callback(err); }
				if (res.documents[0].errmsg) { return callback(new Error(res.documents[0].errmsg)); }

				//res.documents[0].results = [];
				var candidates = res.documents[0].results.map(function (element) {

					if ((element.dis * EARTH_RADIUS) / 1000 < 1) {
						element.distance = Math.round(element.dis * EARTH_RADIUS) + " m";
					}
					else {
						element.distance = Math.round((element.dis * EARTH_RADIUS) / 1000) + " km";
					}

					return element;
				});

				return callback(null, candidates);
			});
		});
	};

	this.disconnect = function disconnect(callback) {
		if (internalConnection) {
			internalConnection = undefined;
		}
		mongooseInstance.disconnect(callback);
	};

	this.dispose = function dispose(callback) {
		// Close connection...
		self.disconnect(callback);
		// Clean up other stuff!
	};
}
738203
function getCollection(key, collectionName, database, options, callback) {
    getDatabaseCached(database, options, getOrCreateCollection)

    function getOrCreateCollection(err, db) {
        if (err) {
            return callback(err)
        }

        // get the collection
        db.collection(collectionName, extend({
            safe: true
        }, options.collectionOptions), createIfNotExist)

        function createIfNotExist(err, collection) {
            // if not exist create it
            if (err && err.message.indexOf(" does not exist") !== -1) {
                return db.createCollection(collectionName, extend({
                    safe: true
                }, options.createCollectionOptions), returnCollection)
            }

            if (err) {
                return callback(err)
            }

            callback(null, collection)
        }
    }

    function returnCollection(err, col) {
        if (err) {
            return callback(err)
        }

        callback(null, col)
    }
}