I'm using Node.js, with Dust.js templates that populate a hierarchical list with values from MongoDB via Mongoose. Trying to filter the data before it gets to the template would obviously be ideal, but I've found very little to help me figure out how to do this, so I'm doing it client side, via jQuery. This code is a serious piece of hackery, so please excuse it! But, at least for the first level of merging, it works.
My Mongoose data populates a drill down, hierarchial menu (a simple ul li type list structure in the HTML) of card decks that are arranged in categories and subcategories. Not every deck will have a subcategory, or the same number of subcategories. These are embedded in each deck, as I'm truly embracing the noSQL idea here! But coming from MySQL this is definitely not as easy to arrange in Mongoose.
So as the category and subcategories are embedded in each deck's JSON, I need to merge all categories, then subcategory 1 by one, so the decks go into the appropriate spot for navigating to the deck's data quickly.
The code I wrote today (as I said it's pretty hideous!) will merge the top level of the list. After running this code, for the top level categories with a duplicate, they are merged, with all children preserved.
My question: I'd like to vastly improve this code. Right now I'm looking at creating a function like this for each of my 4 or 5 levels, which confines me in a way I don't want to be confined (what if a subject really needs 6 levels?) Specifically, I'd like:
a way to merge portions of a list, including the children, that recursively looks to see if there are duplicate subjects on the next level.
would it be smart to begin merging from the bottom level instead?
As I said this would probably be better done by filtering the data before the template is rendered, but I haven't tried to think that one out yet.
Here is my code:
function mergeLevel1() {
  var count = 0;  
  var subcatText;
  var subcatTextCurrent;
  $.each($("ul.rootlist > li").not("ul li ul a"), function() {
    var firstNode = $(this)
    var nodeText = $("a:first", this).text();
    //toastr.warning('nodeText is ' + nodeText)
    $.each($("ul.rootlist > li").not("ul li ul a").not(firstNode), function() {    
      var siblingNode = $(this)
      var siblingText = $("a:first", this).text();
      //toastr.info('running sibling,  siblingText is ' + siblingText)    
      if (nodeText == siblingText) {
        toastr.info('i found a duplicate for ' + siblingText)   
        siblingNode.children().find('li').each(function(){
          if (count == 0) {
            subcatText = $(this).text(); 
          }
          subcatTextCurrent = $(this).text(); 
          count++       
          toastr.warning("found children of a duplicate " + $(this).text())
          //var targetNode = $("a:first", theNode).text()
          toastr.info('try appending to ' + '#'+siblingText+'_ul'+'_'+subcatText)
          if (count > 1) {
            toastr.error('moving node!')
            $(this).appendTo('#'+siblingText+'_ul_'+subcatText);
          }
        })
      }
    });
    removeEmpties();    
  });
  // end merge level 1
}
function removeEmpties() {
$('ul:empty').parent().remove();
}