def generate_aggregate(blocs=[], motion_ids=[], filters={}): keys = set(blocs) spec = dict(filters) if len(motion_ids): spec['motion.motion_id'] = {'$in': motion_ids} keys.add('motion.motion_id') options = get_options() data = {} # Aggregate on the server. for cell in votes.group(keys, spec, {"votes": {}, 'num_votes': 0}, REDUCE): key = repr([cell.get(k) for k in set(keys)]) if not key in data: data[key] = { 'counts': defaultdict(int), 'bloc': {}, 'stats': { 'num_motions': 0, 'num_votes': 0 } } for option in options: v = cell.get('votes').get(option, 0) data[key]['counts'][option] += v for k, v in cell.items(): if k in blocs: data[key]['bloc'][k] = v data[key]['motion_id'] = cell.get('motion.motion_id') data[key]['stats']['num_motions'] += 1 data[key]['stats']['num_votes'] += cell['num_votes'] return data.values()
def generate_stances(blocs=[], issue_ids=[], filters={}): keys = set(blocs) _filt = {} if len(issue_ids): _filt = {'_id': {'$in': [ObjectId(i) for i in issue_ids]}} issue_objs = list(issues.find(_filt)) motion_issues = defaultdict(list) for issue in issue_objs: for motion in issue.get('motions', []): motion_issues[motion['motion_id']].append((issue, motion)) spec = dict(filters) spec['motion.motion_id'] = {'$in': motion_issues.keys()} keys.add('motion.motion_id') options = get_options() data = {} # Aggregate on the server. for cell in votes.group(keys, spec, {"votes": {}, 'num_votes': 0}, REDUCE): # Aggregate by issue locally. for issue, mdata in motion_issues.get(cell.get('motion.motion_id')): # Output cell key. key = repr([issue.get('_id')] + [cell.get(k) for k in set(blocs)]) if not key in data: data[key] = { 'issue': issue, 'counts': defaultdict(int), 'weighted': defaultdict(int), 'bloc': {}, 'stats': { 'num_motions': 0, 'num_votes': 0, 'max_score': 0, 'min_score': 0 } } for option in options: v = cell.get('votes').get(option, 0) data[key]['counts'][option] += v data[key]['weighted'][option] += v * get_weight(mdata, option) for k, v in cell.items(): if k in blocs: data[key]['bloc'][k] = v data[key]['stats']['num_motions'] += 1 data[key]['stats']['num_votes'] += cell['num_votes'] weights = map(lambda x: get_weight(mdata, x), options) data[key]['stats']['max_score'] += cell['num_votes'] * max(weights) data[key]['stats']['min_score'] += cell['num_votes'] * min(weights) blocs = [] for bloc in data.values(): # determine the full range of available values: value_range = bloc['stats']['max_score'] - bloc['stats']['min_score'] # sum up 'yes' and 'no' values: bloc_value = sum(bloc['weighted'].values()) # make the bloc value fall in between 0 and value_range normalized_value = bloc_value + (bloc['stats']['min_score'] * -1) # calculate a score based on the normalized value and the value range bloc['match'] = normalized_value / max(1, value_range) blocs.append(bloc) return blocs