def _get_aggregated_query(self, start, limit): max_size = (start or 0) + (limit or 0) query = HQESQuery(self.table_name).size(0) for filter in self.filters: query = query.filter(filter) innermost_agg_col = self.aggregation_columns[-1] innermost_agg = TermsAggregation(innermost_agg_col, innermost_agg_col) aggregations = [] for col in self.top_level_columns: for agg in col.aggregations(self.config, self.lang): innermost_agg.aggregation(agg) top_agg = innermost_agg # go through aggregations in reverse order so that they are nested properly # todo: Refactor NestedTermAggregationsHelper to support this use case for agg_column in self.aggregation_columns[:-1][::-1]: top_agg = TermsAggregation(agg_column, agg_column).aggregation(top_agg) top_agg.size(max_size) if self.order_by: # todo sort by more than one column # todo sort by by something other than the first aggregate column col, desc = self.order_by[0] if col == self.aggregation_columns[ 0] or col == self.top_level_columns[0].field: top_agg = top_agg.order('_term', desc) query = query.aggregation(top_agg) return query.run()
def get_form_counts_by_user_xmlns(domain, startdate, enddate, user_ids=None, xmlnss=None, by_submission_time=True): missing_users = False date_filter_fn = submitted_filter if by_submission_time else completed_filter query = ( FormES() .domain(domain) .filter(date_filter_fn(gte=startdate, lt=enddate)) .aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TermsAggregation('app_id', 'app_id').aggregation( TermsAggregation('xmlns', 'xmlns') ) ) ) .size(0) ) if user_ids: query = (query .user_ids_handle_unknown(user_ids) .remove_default_filter('has_user')) missing_users = None in user_ids if missing_users: query = query.aggregation( MissingAggregation('missing_user_id', 'form.meta.userID').aggregation( TermsAggregation('app_id', 'app_id').aggregation( TermsAggregation('xmlns', 'xmlns') ) ) ) if xmlnss: query = query.xmlns(xmlnss) counts = defaultdict(lambda: 0) aggregations = query.run().aggregations user_buckets = aggregations.user_id.buckets_list if missing_users: user_buckets.append(aggregations.missing_user_id.bucket) for user_bucket in user_buckets: app_buckets = user_bucket.app_id.buckets_list for app_bucket in app_buckets: xmlns_buckets = app_bucket.xmlns.buckets_list for xmlns_bucket in xmlns_buckets: key = (user_bucket.key, app_bucket.key, xmlns_bucket.key) counts[key] = xmlns_bucket.doc_count return counts
def get_form_count_breakdown_for_domain(domain): query = (FormES(for_export=True).domain(domain).aggregation( TermsAggregation("app_id", "app_id").aggregation( TermsAggregation("xmlns", "xmlns.exact"))).remove_default_filter( "has_xmlns").remove_default_filter("has_user").size(0)) query_result = query.run() form_counts = {} for app_id, bucket in query_result.aggregations.app_id.buckets_dict.items( ): for sub_bucket in bucket.xmlns.buckets_list: xmlns = sub_bucket.key form_counts[(domain, app_id, xmlns)] = sub_bucket.doc_count return form_counts
def get_all_xmlns_app_id_pairs_submitted_to_in_domain(domain): query = (FormES().domain(domain).aggregation( TermsAggregation("app_id", "app_id").aggregation( TermsAggregation("xmlns", "xmlns.exact"))).remove_default_filter( "has_xmlns").remove_default_filter("has_user").size(0)) query_result = query.run() form_counts = set() for app_id, bucket in query_result.aggregations.app_id.buckets_dict.iteritems( ): for sub_bucket in bucket.xmlns.buckets_list: xmlns = sub_bucket.key form_counts.add((xmlns, app_id)) return form_counts
def get_form_count_breakdown_for_domain(domain): query = (FormES( es_instance_alias=ES_EXPORT_INSTANCE).domain(domain).aggregation( TermsAggregation("app_id", "app_id").aggregation( TermsAggregation( "xmlns", "xmlns.exact"))).remove_default_filter( "has_xmlns").remove_default_filter("has_user").size(0)) query_result = query.run() form_counts = {} for app_id, bucket in six.iteritems( query_result.aggregations.app_id.buckets_dict): for sub_bucket in bucket.xmlns.buckets_list: xmlns = sub_bucket.key form_counts[(domain, app_id, xmlns)] = sub_bucket.doc_count return form_counts
def get_domain_device_breakdown_es(domain_name, monthspan): query = FormES(for_export=True).domain(domain_name).submitted( gte=monthspan.startdate, lt=monthspan.computed_enddate, ).aggregation(TermsAggregation('device_id', 'form.meta.deviceID')).size(0) return query.run().aggregations.device_id.counts_by_bucket()
def get_domain_device_breakdown_es(domain_name, monthspan): query = FormES(es_instance_alias=ES_EXPORT_INSTANCE).domain(domain_name).submitted( gte=monthspan.startdate, lt=monthspan.computed_enddate, ).aggregation(TermsAggregation('device_id', 'form.meta.deviceID')).size(0) return query.run().aggregations.device_id.counts_by_bucket()
def get_last_forms_by_app(user_id): """ gets the last form submission for each app for a given user id :param user_id: id of a couch user :return: last form submission for every app that user has submitted """ query = ( FormES() .user_id(user_id) .aggregation( TermsAggregation('app_id', 'app_id').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'received_on', is_ascending=False, ) ) ) .size(0) ) aggregations = query.run().aggregations buckets_dict = aggregations.app_id.buckets_dict result = [] for app_id, bucket in buckets_dict.items(): result.append(bucket.top_hits_last_form_submissions.hits[0]) return result
def _cases_created_per_user_per_month(self, case_type=None): query = (CaseES(es_instance_alias=ES_EXPORT_INSTANCE).domain( self.domain).opened_range( gte=self.date_start, lt=self.date_end).aggregation( TermsAggregation('cases_per_user', 'owner_id', size=100).aggregation( DateHistogram('cases_by_date', 'opened_on', interval='month')))) if case_type: query = query.case_type(case_type) results = query.size(0).run() stats = defaultdict(list) cases_per_user = results.aggregations.cases_per_user for bucket in cases_per_user.buckets_list: counts_by_date = { b['key_as_string']: b['doc_count'] for b in bucket.cases_by_date.normalized_buckets } for key, count in counts_by_date.items(): stats[key].append(count) final_stats = [] for month, case_count_list in sorted(list(stats.items()), key=lambda r: r[0]): final_stats.append( (month, sum(case_count_list) // len(case_count_list))) suffix = '' if case_type: suffix = '(case type: %s)' % case_type self._print_table( ['Month', 'Cases created per user %s' % suffix], final_stats)
def _cases_updated_per_user_per_month(self): results = (CaseES(es_instance_alias=ES_EXPORT_INSTANCE).domain( self.domain).active_in_range( gte=self.date_start, lt=self.date_end).aggregation( TermsAggregation( 'cases_per_user', 'owner_id', size=100).aggregation( NestedAggregation( 'actions', 'actions').aggregation( DateHistogram( 'cases_by_date', 'server_date', interval='month')))).size(0).run()) stats = defaultdict(list) cases_per_user = results.aggregations.cases_per_user for bucket in cases_per_user.buckets_list: counts_by_date = { b['key_as_string']: b['doc_count'] for b in bucket.actions.cases_by_date.normalized_buckets } for key, count in counts_by_date.items(): stats[key].append(count) final_stats = [] for month, case_count_list in sorted(list(stats.items()), key=lambda r: r[0]): final_stats.append( (month, sum(case_count_list) // len(case_count_list))) self._print_table(['Month', 'Cases updated per user'], final_stats)
def get_last_submission_time_for_users(domain, user_ids, datespan, for_export=False): def convert_to_date(date): return string_to_datetime(date).date() if date else None query = (FormES( for_export=for_export).domain(domain).user_id(user_ids).submitted( gte=datespan.startdate.date(), lte=datespan.enddate.date()).aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'received_on', is_ascending=False, include='received_on', ))).size(0)) aggregations = query.run().aggregations buckets_dict = aggregations.user_id.buckets_dict result = {} for user_id, bucket in buckets_dict.items(): result[user_id] = convert_to_date( bucket.top_hits_last_form_submissions.hits[0]['received_on']) return result
def test_nesting_aggregations(self): json_output = { "query": { "filtered": { "filter": { "and": [{ "match_all": {} }] }, "query": { "match_all": {} } } }, "aggs": { "users": { "terms": { "field": "user_id", "size": SIZE_LIMIT }, "aggs": { "closed": { "filter": { "term": { "closed": True } } } } }, "total_by_status": { "filters": { "filters": { "closed": { "term": { "closed": True } }, "open": { "term": { "closed": False } } } } } }, "size": SIZE_LIMIT } query = HQESQuery('cases').aggregations([ TermsAggregation("users", 'user_id').aggregation( FilterAggregation('closed', filters.term('closed', True))), FiltersAggregation('total_by_status').add_filter( 'closed', filters.term('closed', True)).add_filter('open', filters.term('closed', False)) ]) self.checkQuery(query, json_output)
def test_terms_aggregation_with_order(self): json_output = { "query": { "filtered": { "filter": { "and": [{ "match_all": {} }] }, "query": { "match_all": {} } } }, "aggs": { "name": { "terms": { "field": "name", "size": 1000000, "order": [{ "sort_field": "asc" }] }, }, }, "size": SIZE_LIMIT } query = HQESQuery('cases').aggregation( TermsAggregation('name', 'name').order('sort_field')) self.checkQuery(query, json_output)
def get_last_submission_time_for_users(domain, user_ids, datespan, es_instance_alias=ES_DEFAULT_INSTANCE): def convert_to_date(date): return string_to_datetime(date).date() if date else None query = (FormES(es_instance_alias=es_instance_alias).domain( domain).user_id(user_ids).completed( gte=datespan.startdate.date(), lte=datespan.enddate.date()).aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'form.meta.timeEnd', is_ascending=False, include='form.meta.timeEnd', ))).size(0)) aggregations = query.run().aggregations buckets_dict = aggregations.user_id.buckets_dict result = {} for user_id, bucket in buckets_dict.items(): result[user_id] = convert_to_date( bucket.top_hits_last_form_submissions.hits[0]['form']['meta'] ['timeEnd']) return result
def get_all_user_ids_submitted(domain, app_ids=None): query = (FormES().domain(domain).aggregation( TermsAggregation('user_id', 'form.meta.userID')).size(0)) if app_ids: query = query.app(app_ids) return list(query.run().aggregations.user_id.buckets_dict)
def _get_aggregated_query(self, start, limit): max_size = (start or 0) + (limit or 0) query = HQESQuery(self.table_name).size(0) for filter in self.filters: query = query.filter(filter) innermost_agg_col = self.aggregation_columns[-1] innermost_agg = TermsAggregation(innermost_agg_col, innermost_agg_col, size=max_size) aggregations = [] for col in self.top_level_columns: for agg in col.aggregations(self.config, self.lang): innermost_agg.aggregation(agg) top_agg = innermost_agg # go through aggregations in reverse order so that they are nested properly for agg_column in self.aggregation_columns[:-1][::-1]: top_agg = TermsAggregation(agg_column, agg_column, size=max_size).aggregation(top_agg) if self.order_by: col, desc = self.order_by[0] valid_columns = ( self.aggregation_columns[0], self.top_level_columns[0].field, self.top_level_columns[0].column_id ) if col in valid_columns: top_agg = top_agg.order('_term', desc) query = query.aggregation(top_agg) return query.run()
def _get_aggregated_query(self, start, limit): max_size = (start or 0) + (limit or 0) query = HQESQuery(self.table_name).size(0) for filter in self.filters: query = query.filter(filter) innermost_agg_col = self.aggregation_columns[-1] innermost_agg = TermsAggregation(innermost_agg_col, innermost_agg_col) aggregations = [] for col in self.top_level_columns: for agg in col.aggregations(self.config, self.lang): innermost_agg.aggregation(agg) top_agg = innermost_agg # go through aggregations in reverse order so that they are nested properly # todo: Refactor NestedTermAggregationsHelper to support this use case for agg_column in self.aggregation_columns[:-1][::-1]: top_agg = TermsAggregation(agg_column, agg_column).aggregation(top_agg) top_agg.size(max_size) if self.order_by: # todo sort by more than one column # todo sort by by something other than the first aggregate column col, desc = self.order_by[0] if col == self.aggregation_columns[0] or col == self.top_level_columns[0].field: top_agg = top_agg.order('_term', desc) query = query.aggregation(top_agg) return query.run()
def get_form_duration_stats_by_user( domain, app_id, xmlns, user_ids, startdate, enddate, by_submission_time=True): """Gets stats on the duration of a selected form grouped by users""" date_filter_fn = submitted_filter if by_submission_time else completed_filter missing_users = None in user_ids query = ( FormES() .domain(domain) .user_ids_handle_unknown(user_ids) .remove_default_filter('has_user') .xmlns(xmlns) .filter(date_filter_fn(gte=startdate, lt=enddate)) .aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( ExtendedStatsAggregation( 'duration_stats', 'form.meta.timeStart', script="doc['form.meta.timeEnd'].value - doc['form.meta.timeStart'].value", ) ) ) .size(0) ) if app_id: query = query.app(app_id) if missing_users: query = query.aggregation( MissingAggregation('missing_user_id', 'form.meta.userID').aggregation( ExtendedStatsAggregation( 'duration_stats', 'form.meta.timeStart', script="doc['form.meta.timeEnd'].value - doc['form.meta.timeStart'].value", ) ) ) result = {} aggregations = query.run().aggregations if missing_users: result[MISSING_KEY] = aggregations.missing_user_id.bucket.duration_stats.result buckets_dict = aggregations.user_id.buckets_dict for user_id, bucket in buckets_dict.iteritems(): result[user_id] = bucket.duration_stats.result return result
def get_case_types_from_apps(domain): """ Get the case types of modules in applications in the domain. :returns: A set of case_types """ case_types_agg = NestedAggregation('modules', 'modules').aggregation( TermsAggregation('case_types', 'modules.case_type.exact')) q = (AppES().domain(domain).is_build(False).size(0).aggregation( case_types_agg)) return set(q.run().aggregations.modules.case_types.keys) - {''}
def get_forms_for_users(domain, user_ids, start, end): query = (FormES().domain(domain).submitted( gte=start, lte=end).user_id(user_ids).aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TopHitsAggregation(name='top_hits_user_submissions', size=1000000, include=['form.case', 'form.@xmlns']))).size(0)) aggregations = query.run().aggregations return aggregations.user_id.buckets_dict
def get_all_xmlns_app_id_pairs_submitted_to_in_domain(domain): """This is used to get (XMLNS, app_id) from submitted forms. The results get combined with data from all current app versions which means that this is only used to get (XMLNS, app_id) combos from forms submitted in the past which no longer have a corresponding form in the app (e.g. form deleted) Given that we can cache this for a long period of time under the assumption that a user isn't going to submit a form and then delete it from their app immediately. """ query = (FormES().domain(domain).aggregation( TermsAggregation("app_id", "app_id").aggregation( TermsAggregation("xmlns", "xmlns.exact"))).remove_default_filter( "has_xmlns").remove_default_filter("has_user").size(0)) query_result = query.run() form_counts = set() for app_id, bucket in query_result.aggregations.app_id.buckets_dict.items( ): for sub_bucket in bucket.xmlns.buckets_list: xmlns = sub_bucket.key form_counts.add((xmlns, app_id)) return form_counts
def _get_aggregated_query(self, start, limit): max_size = (start or 0) + (limit or 0) query = HQESQuery(self.table_name).size(0) for filter in self.filters: query = query.filter(filter) top_agg = TermsAggregation(self.aggregation_columns[0], self.aggregation_columns[0], size=max_size) for agg_column in self.aggregation_columns[1:]: # todo support multiple aggregations pass aggregations = [] for col in self.top_level_columns: if col.type == 'expanded': for sub_col in get_expanded_column_config( self.config, col, 'en').columns: aggregations.append(sub_col.aggregation) elif col.type == 'field': if col.aggregation == 'sum': # todo push this to the column aggregations.append(SumAggregation(col.field, col.field)) for agg in aggregations: top_agg = top_agg.aggregation(agg) if self.order_by: # todo sort by more than one column # todo sort by by something other than the first aggregate column col, desc = self.order_by[0] if col == self.aggregation_columns[ 0] or col == self.top_level_columns[0].field: top_agg = top_agg.order('_count', desc) query = query.aggregation(top_agg) return query.run()
def get_last_form_submissions_by_user(domain, user_ids, app_id=None, xmlns=None): missing_users = None in user_ids query = ( FormES() .domain(domain) .user_ids_handle_unknown(user_ids) .remove_default_filter('has_user') .aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'received_on', is_ascending=False, ) ) ) .size(0) ) if app_id: query = query.app(app_id) if xmlns: query = query.xmlns(xmlns) result = {} if missing_users: query = query.aggregation( MissingAggregation('missing_user_id', 'form.meta.userID').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'received_on', is_ascending=False, ) ) ) aggregations = query.run().aggregations if missing_users: result[MISSING_KEY] = aggregations.missing_user_id.bucket.top_hits_last_form_submissions.hits buckets_dict = aggregations.user_id.buckets_dict for user_id, bucket in six.iteritems(buckets_dict): result[user_id] = bucket.top_hits_last_form_submissions.hits return result
def get_latest_build_ids(domain, app_id, user_ids): query = (FormES(es_instance_alias=ES_EXPORT_INSTANCE).domain(domain).app( [app_id]).user_id(user_ids).aggregation( TermsAggregation('user_id', 'form.meta.userID').aggregation( TopHitsAggregation( 'top_hits_last_form_submissions', 'received_on', is_ascending=False, include=['build_id'], ))).size(0)) aggregations = query.run().aggregations buckets_dict = aggregations.user_id.buckets_dict result = {} for user_id, bucket in buckets_dict.items(): result[user_id] = bucket.top_hits_last_form_submissions.hits[0][ 'build_id'] return result
def _ledgers_per_case(self): db_name = get_db_aliases_for_partitioned_query()[ 0] # just query one shard DB results = (LedgerValue.objects.using(db_name).filter( domain=self.domain).values('case_id').annotate( ledger_count=Count('pk')))[:100] case_ids = set() ledger_count = 0 for result in results: case_ids.add(result['case_id']) ledger_count += result['ledger_count'] if not case_ids: self.stdout.write("Domain has no ledgers") return avg_ledgers_per_case = ledger_count / len(case_ids) case_types_result = CaseES(for_export=True)\ .domain(self.domain).case_ids(case_ids)\ .aggregation(TermsAggregation('types', 'type.exact'))\ .size(0).run() case_types = case_types_result.aggregations.types.keys self.stdout.write('\nCase Types with Ledgers') for type_ in case_types: self._print_value( 'case_type', type_, CaseES().domain(self.domain).case_type(type_).count()) db_name = get_db_aliases_for_partitioned_query()[ 0] # just query one shard DB results = (CommCareCase.objects.using(db_name).filter( domain=self.domain, closed=True, type=type_).annotate( lifespan=F('closed_on') - F('opened_on')).annotate( avg_lifespan=Avg('lifespan')).values('avg_lifespan', flat=True)) self._print_value('Average lifespan for "%s" cases' % type_, results[0]['avg_lifespan']) self._cases_created_per_user_per_month(type_) self._print_value('Average ledgers per case', avg_ledgers_per_case) stats = defaultdict(list) for db_name, case_ids_p in split_list_by_db_partition(case_ids): transactions_per_case_per_month = ( LedgerTransaction.objects.using(db_name).filter( case_id__in=case_ids).annotate( m=Month('server_date'), y=Year('server_date')).values( 'case_id', 'y', 'm').annotate(count=Count('id'))) for row in transactions_per_case_per_month: month = date(row['y'], row['m'], 1) stats[month].append(row['count']) final_stats = [] for month, transaction_count_list in sorted(list(stats.items()), key=lambda r: r[0]): final_stats.append( (month.isoformat(), sum(transaction_count_list) // len(transaction_count_list))) self.stdout.write('Ledger updates per case') self._print_table(['Month', 'Ledgers updated per case'], final_stats)
def _ledgers_per_case(self): results = (LedgerES(es_instance_alias=ES_EXPORT_INSTANCE).domain( self.domain).aggregation( TermsAggregation('by_case', 'case_id', size=100)).size(0).run()) ledgers_per_case = results.aggregations.by_case case_ids = set() ledger_counts = [] for case_id, ledger_count in ledgers_per_case.counts_by_bucket().items( ): case_ids.add(case_id) ledger_counts.append(ledger_count) if not case_ids: self.stdout.write("Domain has no ledgers") return avg_ledgers_per_case = sum(ledger_counts) // len(case_ids) case_types_result = CaseES(es_instance_alias=ES_EXPORT_INSTANCE)\ .domain(self.domain).case_ids(case_ids)\ .aggregation(TermsAggregation('types', 'type'))\ .size(0).run() case_types = case_types_result.aggregations.types.keys self.stdout.write('\nCase Types with Ledgers') for type_ in case_types: self._print_value( 'case_type', type_, CaseES().domain(self.domain).case_type(type_).count()) if should_use_sql_backend(self.domain): db_name = get_db_aliases_for_partitioned_query()[ 0] # just query one shard DB results = (CommCareCaseSQL.objects.using(db_name).filter( domain=self.domain, closed=True, type=type_).annotate( lifespan=F('closed_on') - F('opened_on')).annotate( avg_lifespan=Avg('lifespan')).values( 'avg_lifespan', flat=True)) self._print_value('Average lifespan for "%s" cases' % type_, results[0]['avg_lifespan']) self._cases_created_per_user_per_month(type_) self._print_value('Average ledgers per case', avg_ledgers_per_case) if should_use_sql_backend(self.domain): stats = defaultdict(list) for db_name, case_ids_p in split_list_by_db_partition(case_ids): transactions_per_case_per_month = ( LedgerTransaction.objects.using(db_name).filter( case_id__in=case_ids).annotate( m=Month('server_date'), y=Year('server_date')).values( 'case_id', 'y', 'm').annotate(count=Count('id'))) for row in transactions_per_case_per_month: month = date(row['y'], row['m'], 1) stats[month].append(row['count']) else: transactions_per_case_per_month = (StockTransaction.objects.filter( case_id__in=case_ids).annotate( m=Month('report__date'), y=Year('report__date')).values( 'case_id', 'y', 'm').annotate(count=Count('id'))) stats = defaultdict(list) for row in transactions_per_case_per_month: month = date(row['y'], row['m'], 1) stats[month].append(row['count']) final_stats = [] for month, transaction_count_list in sorted(list(stats.items()), key=lambda r: r[0]): final_stats.append( (month.isoformat(), sum(transaction_count_list) // len(transaction_count_list))) self._print_table(['Month', 'Ledgers updated per case'], final_stats)
def test_result_parsing_complex(self): query = HQESQuery('cases').aggregation( TermsAggregation("users", 'user_id').aggregation( FilterAggregation('closed', filters.term( 'closed', True))).aggregation( FilterAggregation('open', filters.term( 'closed', False)))).aggregation( RangeAggregation('by_date', 'name', [ AggregationRange(end='c'), AggregationRange(start='f'), AggregationRange(start='k', end='p') ])) raw_result = { "aggregations": { "users": { "buckets": [{ "closed": { "doc_count": 0 }, "doc_count": 2, "key": "user1", "open": { "doc_count": 2 } }], "doc_count_error_upper_bound": 0, "sum_other_doc_count": 0 }, "by_date": { "buckets": { "*-c": { "to": "c", "doc_count": 3 }, "f-*": { "from": "f", "doc_count": 8 }, "k-p": { "from": "k", "to": "p", "doc_count": 6 } } } }, } queryset = ESQuerySet(raw_result, deepcopy(query)) self.assertEqual(queryset.aggregations.users.buckets.user1.key, 'user1') self.assertEqual(queryset.aggregations.users.buckets.user1.doc_count, 2) self.assertEqual( queryset.aggregations.users.buckets.user1.closed.doc_count, 0) self.assertEqual( queryset.aggregations.users.buckets.user1.open.doc_count, 2) self.assertEqual( queryset.aggregations.users.buckets_dict['user1'].open.doc_count, 2) self.assertEqual(queryset.aggregations.users.counts_by_bucket(), {'user1': 2}) self.assertEqual(queryset.aggregations.by_date.counts_by_bucket(), { '*-c': 3, 'f-*': 8, 'k-p': 6, })