How do I properly aggregate mongodb results from two separate content types in my node.js app?

How do I properly aggregate results in a view using node.js & mongoose from mongodb. My programmer colleague came up with the following route to aggregate event and blog posts in one list/view of content sorted by day (if both "published" and "promoted" equal 1). The trouble with this is that the list of aggregate results is really just split into two (first events display, then blogs display) when they should render in a truly mixed fashion sorted by date. I would use a join or groupby in mysql but how would I do this type of aggregation in a node.js app with mongodb? Ps, we're using express and mongoose in case that helps.

Update: We've already defined the schema for the two (events and blogs), and there are thousands of records already stored. So the question now is, can we do this client side or do we have to create an index (another collection)? I'm reading up on mongodb's aggregation framework and map reduce as well but I'm not sure if either of those can help me at this point.

    app.get('/promoted/content/:page?', userSession, function(req, res, next) {
var today = todayTimestamp();

var limit = 10;
if(req.params.page) {
    var skip = req.params.page * limit;
} else {
    var skip = 0;
}

async.parallel({
    blogs: function(callback){
        app.Blog.find()
            .where('status').equals(1)
            .where('promote').equals(1)
            .sort('sticky', -1)
            .sort('created', -1)
            .populate('userId')
            .exec(function(err, blogs) {
                if (err) {
                    console.log(err);
                } else {
                    callback(null, blogs);
                }
        });
    },
    events: function(callback){
        app.Event.find()
            .where('status').equals(1)
            .where('promote').equals(1)
            .sort('sticky', -1)
            .sort('created', -1)
            .populate('userId')
            .exec(function(err, events) {
                if (err) {
                    console.log(err);
                } else {
                    callback(null, events);
                }
        });
    }
},
// callback function to render page and pass in all data
function(err, results){

    //add type field to results for logic in mixed output
    for(i = 0; i < results.blogs.length; i++) {
        results.blogs[i].type = 'blog';
    }
    for(i = 0; i < results.events.length; i++) {
        results.events[i].type = 'event';
    }

    //combine results from blogs and events and sort the results
    var promoted = results.events.concat(results.blogs);
    var outputted = false;
    promoted.sort(function( a, b )
    {
      // Sort by key of modification date in each array
      if ( a['changed'] == b['changed'] ) return 0;
      return a['changed'] < b['changed'] ? -1 : -1;
    });

    //create a subset
    var subset = new Array();
    for(var i = skip; i < (limit + skip); i++) {
        subset.push(promoted[i]);
    }

    //check mobile
    if(isMobile(req)) {
        res.render('mobile/fragments/block_posts', { posts: subset, user: req.session.user, message: req.flash()});
    } else {
        res.render('fragments/block_posts', { posts: subset, user: req.session.user, message: req.flash()});
    }
});