0
\$\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\$

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Browse other questions tagged or ask your own question.