1
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.