Relationnal model with Towerjs (coffeescript & mongodb)

281 views Asked by At

I need to recover in towerjs (with mongodb store) quote stock from all stock in all trades of one user. This code don't work, the while loop does not stop, but I do not understand why

    App.Trade.where(userId: @currentUser.get('id')).order("date", "desc").all (error, trades) ->
      idst = {}
      i = 0
      len = trades.length          

      while i < len
        trade = trades[i]
        idst[trade.get('stockTicker')] = 1  if trade.get('stockId') and not idst[trade.get('stockId')]
        i++

      App.Stock.where({ticker: {$in: Object.keys(idst)}}).all (error, stocks) ->
        map = {}
        mapQuote = {}
        i = 0
        len = stocks.length

        while i < len
          stock = stocks[i]
          map[stock.get('ticker')] = stock
          App.QuoteStock.where(ticker: stock.get('ticker')).order("createdAt", "desc").limit(1).first (error, quoteStock) ->
            mapQuote[stock.get('ticker')] = quoteStock
            i++

        i = 0
        len = trades.length
        while i < len
          trade = trades[i]
          trade.stock = map[trade.get('stockTicker')]
          trade.quoteStock = mapQuote[trade.get('stockTicker')]
          i++

        _this.trades = trades
2

There are 2 answers

0
Siwei On

oh my god, your code looks terrible... ( so many i++, i < length, in nested scopes) please... don't write code in that way, smells too bad. nested loops leads to your code too hard to read, especially there are shadow variables.

so, the problem you met is "Shadow variables", which looks like:

some_var = "I am normal"
shadow_it = -> 
  some_var = "this is the shadow"
  # blabla

I suggest you improve the implementation of your algorithm, avoid using shadow variables.

0
Lance On

It looks like there are a couple places where the problem might be occurring.

In the first while loop, I'm not sure if you meant this:

idst[trade.get('stockTicker')] = 1  if trade.get('stockId') and not idst[trade.get('stockId')]

That last bit, idst[trade.get('stockId')] is never set. But that doesn't interrupt the while loop, so probably not the issue.

The main thing is, because the second and third while loop are inside the asynchronous App.Trade.where function, they're not going to work correctly.

Also, the following will not work because the asynchronous code is called each iteration:

while i < len
  stock = stocks[i]
  map[stock.get('ticker')] = stock
  App.QuoteStock.where(ticker: stock.get('ticker')).order("createdAt", "desc").limit(1).first (error, quoteStock) ->
    mapQuote[stock.get('ticker')] = quoteStock
    i++

Instead you need to use an asynchronous loop: https://github.com/caolan/async. You can do that like this:

async = require('async')

stocksIterator = (stock, next) ->
  map[stock.get('ticker')] = stock
  App.QuoteStock.where(ticker: stock.get('ticker')).order("createdAt", "desc").limit(1).first (error, quoteStock) ->
    mapQuote[stock.get('ticker')] = quoteStock
    next()

async.forEachSeries stocks, stocksIterator, (error) ->
  tradesIterator = (trade, next) ->
    trade.stock = map[trade.get('stockTicker')]
    trade.quoteStock = mapQuote[trade.get('stockTicker')]
    next()

  async.forEachSeries trades, tradesIterator, (error) ->
    _this.trades = trades

Also, if I were you I would put each of these iterators into separate functions, or use different index variables (i, j, k for example). It makes mentally dealing with the async nature of this easier.

Let me know if that works. Cheers.