I have a situation where I have multiple objects that each needs to connect to a different MongoDB URI.
I am currently testing this using Mongolia but the concept should be the same if I were to use the collection()
method of MongoDB's native driver.
Mongolia requires a db
object when creating a new model, and since I do not have this object from start, I thought it would be better to callback the hell out of it.
I do not wish to force all objects to connect to their databases from the start so it seems that nesting the callbacks is the way to go.
MongoClient = (require 'mongodb').MongoClient
mongolia = require 'mongolia'
modelFactory = (db, modelName, cb) ->
model = mongolia.model db, modelName
cb undefined, model
class SomethingWithDb
tag: undefined
databaseUri: undefined
databaseInstance: undefined
models: {}
collections: {}
log: (text) =>
console.log "[#{@tag}] #{text}"
database: (cb) =>
if not @databaseInstance?
@log 'database() > Creating new database instance.'
MongoClient.connect @databaseUri, {}, (err, db) =>
return cb err if err
@log 'database() > Database instance ready, returning.'
@databaseInstance = db
cb undefined, @databaseInstance
else
@log 'database() > Database instance existed, returning.'
cb undefined, @databaseInstance
model: (modelName, cb) =>
if modelName not of @models
@log "model(#{modelName}) > Creating new model."
@database (errDb, db) =>
return cb errDb if errDb
modelFactory db, modelName, (errFactory, model) =>
@log "model(#{modelName}) > Model created, returning."
return cb errFactory if errFactory
@models[modelName] = model
cb undefined, model
else
@log "model(#{modelName}) > Model existed, returning."
cb undefined, @models[modelName]
collection: (collectionName, cb) =>
if collectionName not of @collections
@log "collection(#{collectionName}) > Creating new collection."
if not @databaseInstance?
@database (errDb, db) =>
return cb errDb if errDb
@log "collection(#{collectionName}) > Collection created (new db), returning."
@collections[collectionName] = db.collection collectionName
cb undefined, @collections[collectionName]
else
@log "collection(#{collectionName}) > Collection created (existing db), returning."
cb undefined, @databaseInstance.collection collectionName
else
@log "collection(#{collectionName}) > Collection existed, returning."
cb undefined, @collections[collectionName]
constructor: (@tag, @databaseUri, @databaseOptions) ->
one = new SomethingWithDb "mongodb://localhost/test-one"
two = new SomethingWithDb "mongodb://localhost/test-two"
one.model 'user', (errModel, user) ->
user.insert name: 'test', (errInsert, respInsert) ->
one.model 'user', (_errModel, _user) ->
_user.findOne name: 'test', (_errFind, _result) ->
console.info _result
two.model 'user', (errModel, user) ->
user.insert name: 'test-two', (errInsert, respInsert) ->
user.findOne name: 'test-two', (errFind, result) ->
console.info result
The output is something like this:
# [one] model(user) > Creating new model. # [one] database() > Creating new database instance. # [two] model(user) > Creating new model. # [two] database() > Creating new database instance. # [two] database() > Database instance ready, returning. # [two] model(user) > Model created, returning. # [one] database() > Database instance ready, returning. # [one] model(user) > Model created, returning. # [one] model(user) > Model existed, returning.
I have included a @collection()
method that is not tested but should provide a hint to other uses.
Is the logic behind this correct or is there some better way to do this that I am not aware of? I'd be also very interested in any possible code or flow optimizations that might make this saner or more solid.