'This method makes use of the aggregation framework to produce
top values for a given field or pseudo-field. Pseudo-fields are:
- category / asnum / country / net[:mask]
- port
- port:open / :closed / :filtered / :<servicename>
- portlist:open / :closed / :filtered
- countports:open / :closed / :filtered
- service / service:<portnbr>
- product / product:<portnbr>
- cpe / cpe.<part> / cpe:<cpe_spec> / cpe.<part>:<cpe_spec>
- devicetype / devicetype:<portnbr>
- script:<scriptid> / script:<port>:<scriptid>
/ script:host:<scriptid>
- cert.* / smb.* / sshkey.* / ike.*
- modbus.* / s7.* / enip.*
- mongo.dbs.*
- vulns.*
- screenwords
- file.* / file.*:scriptid
- hop'

def topvalues(self, field, flt=None, topnbr=10, sort=None, limit=None, skip=None, least=False, archive=False, aggrflt=None, specialproj=None, specialflt=None):

    null_if_empty = (lambda val: (val if val else None))
    outputproc = None
    if (flt is None):
        flt = self.flt_empty
    if (aggrflt is None):
        aggrflt = self.flt_empty
    if (specialflt is None):
        specialflt = []
    if (field == 'category'):
        field = 'categories'
    elif (field == 'country'):
        flt = self.flt_and(flt, {'infos.country_code': {'$exists': True}})
        field = 'infos.country_code'
        outputproc = (lambda x: {'count': x['count'], '_id': (x['_id'], self.globaldb.data.country_name_by_code(x['_id']))})
    elif (field == 'city'):
        flt = self.flt_and(flt, {'infos.country_code': {'$exists': True}}, {'infos.city': {'$exists': True}})
        specialproj = {'_id': 0, 'city': {'$concat': ['$infos.country_code', '###', '$infos.city']}}
        field = 'city'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(x['_id'].split('###', 1))})
    elif (field == 'asnum'):
        flt = self.flt_and(flt, {'infos.as_num': {'$exists': True}})
        field = 'infos.as_num'
    elif (field == 'as'):
        flt = self.flt_and(flt, {'infos.as_num': {'$exists': True}})
        specialproj = {'_id': 0, 'as': {'$concat': [{'$toLower': '$infos.as_num'}, '###', {'$ifNull': ['$infos.as_name', '']}]}}
        field = 'as'
        outputproc = (lambda x: {'count': x['count'], '_id': ((None, None) if (x['_id'] is None) else tuple(((int(y) if (i == 0) else y) for (i, y) in enumerate(x['_id'].split('###')))))})
    elif ((field == 'net') or field.startswith('net:')):
        field = 'addr'
        mask = (int(field.split(':', 1)[1]) if (':' in field) else 24)
        if (self.server_info['versionArray'] >= [3, 2]):
            specialproj = {'_id': 0, 'addr': {'$floor': {'$divide': ['$addr', (2 ** (32 - mask))]}}}
        else:
            specialproj = {'_id': 0, 'addr': {'$subtract': [{'$divide': ['$addr', (2 ** (32 - mask))]}, {'$mod': [{'$divide': ['$addr', (2 ** (32 - mask))]}, 1]}]}}
        outputproc = (lambda x: {'count': x['count'], '_id': ('%s/%d' % (utils.int2ip((x['_id'] * (2 ** (32 - mask)))), mask))})
    elif ((field == 'port') or field.startswith('port:')):
        if (field == 'port'):
            info = {'$exists': True}
            flt_field = 'ports.state_state'
        else:
            info = field.split(':', 1)[1]
            flt_field = ('ports.%s' % ('state_state' if (info in ['open', 'filtered', 'closed']) else 'service_name'))
        field = 'ports.port'
        flt = self.flt_and(flt, {flt_field: info})
        specialproj = {'_id': 0, flt_field: 1, field: 1, 'ports.protocol': 1}
        specialflt = [{'$match': {flt_field: info}}, {'$project': {field: {'$concat': ['$ports.protocol', '###', {'$toLower': '$ports.port'}]}}}]
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(((int(y) if (i == 1) else y) for (i, y) in enumerate(x['_id'].split('###'))))})
    elif field.startswith('portlist:'):
        specialproj = {'ports.port': 1, 'ports.protocol': 1, 'ports.state_state': 1}
        specialflt = [{'$project': {'ports.port': 1, 'ports.protocol': 1, 'ports.state_state': 1}}, {'$project': {'ports': {'$ifNull': ['$ports', []]}}}, {'$redact': {'$cond': {'if': {'$eq': [{'$ifNull': ['$ports', None]}, None]}, 'then': {'$cond': {'if': {'$eq': ['$state_state', field.split(':', 1)[1]]}, 'then': '$$KEEP', 'else': '$$PRUNE'}}, 'else': '$$DESCEND'}}}, {'$project': {'ports.port': 1, 'ports.protocol': 1}}, {'$project': {'portlist': '$ports'}}]
        field = 'portlist'
        outputproc = (lambda x: {'count': x['count'], '_id': [(y['protocol'], y['port']) for y in x['_id']]})
    elif field.startswith('countports:'):
        state = field.split(':', 1)[1]
        if (state == 'open'):
            field = 'openports.count'
        else:
            specialproj = {'_id': 0, 'ports.state_state': 1}
            specialflt = [{'$project': {'ports': {'$ifNull': ['$ports', []]}}}, {'$redact': {'$cond': {'if': {'$eq': [{'$ifNull': ['$ports', None]}, None]}, 'then': {'$cond': {'if': {'$eq': ['$state_state', state]}, 'then': '$$KEEP', 'else': '$$PRUNE'}}, 'else': '$$DESCEND'}}}, {'$project': {'countports': {'$size': '$ports'}}}]
            field = 'countports'
    elif (field == 'service'):
        flt = self.flt_and(flt, self.searchopenport())
        specialproj = {'_id': 0, 'ports.state_state': 1, 'ports.service_name': 1}
        specialflt = [{'$match': {'ports.state_state': 'open'}}, {'$project': {'ports.service_name': {'$ifNull': ['$ports.service_name', '']}}}]
        field = 'ports.service_name'
        outputproc = (lambda x: {'count': x['count'], '_id': (x['_id'] if x['_id'] else None)})
    elif field.startswith('service:'):
        port = int(field.split(':', 1)[1])
        flt = self.flt_and(flt, self.searchport(port))
        specialproj = {'_id': 0, 'ports.port': 1, 'ports.service_name': 1}
        specialflt = [{'$match': {'ports.port': port}}, {'$project': {'ports.service_name': {'$ifNull': ['$ports.service_name', '']}}}]
        field = 'ports.service_name'
    elif (field == 'product'):
        flt = self.flt_and(flt, self.searchopenport())
        specialproj = {'_id': 0, 'ports.state_state': 1, 'ports.service_name': 1, 'ports.service_product': 1}
        specialflt = [{'$match': {'ports.state_state': 'open'}}, {'$project': {'ports.service_product': {'$concat': [{'$ifNull': ['$ports.service_name', '']}, '###', {'$ifNull': ['$ports.service_product', '']}]}}}]
        field = 'ports.service_product'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(((elt if elt else None) for elt in x['_id'].split('###')))})
    elif field.startswith('product:'):
        service = field.split(':', 1)[1]
        if service.isdigit():
            port = int(service)
            flt = self.flt_and(flt, self.searchport(port))
            specialflt = [{'$match': {'ports.port': port}}]
        else:
            flt = self.flt_and(flt, self.searchservice(service))
            specialflt = [{'$match': {'ports.service_name': service}}]
        specialproj = {'_id': 0, 'ports.port': 1, 'ports.service_name': 1, 'ports.service_product': 1}
        specialflt.append({'$project': {'ports.service_product': {'$concat': [{'$ifNull': ['$ports.service_name', '']}, '###', {'$ifNull': ['$ports.service_product', '']}]}}})
        field = 'ports.service_product'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(((elt if elt else None) for elt in x['_id'].split('###')))})
    elif (field == 'version'):
        flt = self.flt_and(flt, self.searchopenport())
        specialproj = {'_id': 0, 'ports.state_state': 1, 'ports.service_name': 1, 'ports.service_product': 1, 'ports.service_version': 1}
        specialflt = [{'$match': {'ports.state_state': 'open'}}, {'$project': {'ports.service_product': {'$concat': [{'$ifNull': ['$ports.service_name', '']}, '###', {'$ifNull': ['$ports.service_product', '']}, '###', {'$ifNull': ['$ports.service_version', '']}]}}}]
        field = 'ports.service_product'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(((elt if elt else None) for elt in x['_id'].split('###')))})
    elif field.startswith('version:'):
        service = field.split(':', 1)[1]
        if service.isdigit():
            port = int(service)
            flt = self.flt_and(flt, self.searchport(port))
            specialflt = [{'$match': {'ports.port': port}}]
        elif (':' in service):
            (service, product) = service.split(':', 1)
            flt = self.flt_and(flt, self.searchproduct(product, service=service))
            specialflt = [{'$match': {'ports.service_name': service, 'ports.service_product': product}}]
        else:
            flt = self.flt_and(flt, self.searchservice(service))
            specialflt = [{'$match': {'ports.service_name': service}}]
        specialproj = {'_id': 0, 'ports.port': 1, 'ports.service_name': 1, 'ports.service_product': 1, 'ports.service_version': 1}
        specialflt.append({'$project': {'ports.service_product': {'$concat': [{'$ifNull': ['$ports.service_name', '']}, '###', {'$ifNull': ['$ports.service_product', '']}, '###', {'$ifNull': ['$ports.service_version', '']}]}}})
        field = 'ports.service_product'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(((elt if elt else None) for elt in x['_id'].split('###')))})
    elif field.startswith('cpe'):
        try:
            (field, cpeflt) = field.split(':', 1)
            cpeflt = cpeflt.split(':', 3)
        except ValueError:
            cpeflt = []
        try:
            field = field.split('.', 1)[1]
        except IndexError:
            field = 'version'
        fields = ['type', 'vendor', 'product', 'version']
        if (field not in fields):
            try:
                field = fields[(int(field) - 1)]
            except (IndexError, ValueError):
                field = 'version'
        cpeflt = zip(fields, (utils.str2regexp(value) for value in cpeflt))
        cpeflt1 = self.searchcpe(**dict(((('cpe_type' if (key == 'type') else key), value) for (key, value) in cpeflt)))
        cpeflt2 = dict(((('cpes.%s' % key), value) for (key, value) in cpeflt))
        fields = fields[:(max(fields.index(field), len(cpeflt)) + 1)]
        flt = self.flt_and(flt, cpeflt1)
        specialproj = dict(((('cpes.%s' % fname), 1) for fname in fields))
        specialproj['_id'] = 0
        concat = [('$cpes.%s' % fields[0])]
        for fname in fields[1:(fields.index(field) + 1)]:
            concat.append(':')
            concat.append(('$cpes.%s' % fname))
        specialflt = []
        if cpeflt2:
            specialflt.append({'$match': cpeflt2})
        specialflt.append({'$project': {('cpes.%s' % field): {'$concat': concat}}})
        field = ('cpes.%s' % field)
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(x['_id'].split(':', 3))})
    elif (field == 'devicetype'):
        field = 'ports.service_devicetype'
    elif field.startswith('devicetype:'):
        port = int(field.split(':', 1)[1])
        flt = self.flt_and(flt, self.searchport(port))
        specialproj = {'_id': 0, 'ports.port': 1, 'ports.service_devicetype': 1}
        specialflt = [{'$match': {'ports.port': port}}, {'$project': {'ports.service_devicetype': 1}}]
        field = 'ports.service_devicetype'
    elif field.startswith('smb.'):
        flt = self.flt_and(flt, self.searchscript(name='smb-os-discovery'))
        if (field == 'smb.dnsdomain'):
            field = 'ports.scripts.smb-os-discovery.domain_dns'
        elif (field == 'smb.forest'):
            field = 'ports.scripts.smb-os-discovery.forest_dns'
        else:
            field = ('ports.scripts.smb-os-discovery.' + field[4:])
    elif (field == 'script'):
        flt = self.flt_and(flt, self.searchscript(name={'$exists': True}))
        field = 'ports.scripts.id'
    elif field.startswith('script:'):
        scriptid = field.split(':', 1)[1]
        flt = self.flt_and(flt, self.searchscript(name={'$exists': True}))
        if (':' in scriptid):
            (port, scriptid) = scriptid.split(':', 1)
            if port.isdigit():
                port = int(port)
            flt = self.flt_and(flt, self.searchport(port))
        else:
            (port, scriptid) = (None, field.split(':', 1)[1])
        specialproj = {'_id': 0, 'ports.scripts.id': 1, 'ports.scripts.output': 1}
        if (port is not None):
            specialproj.update({'ports.port': 1})
        specialflt = [{'$match': ({'ports.scripts.id': scriptid} if (port is None) else {'ports.scripts.id': scriptid, 'ports.port': port})}, {'$project': {'ports.scripts.output': 1}}]
        field = 'ports.scripts.output'
    elif (field == 'domains'):
        flt = self.flt_and(flt, self.searchdomain({'$exists': True}))
        field = 'hostnames.domains'
    elif field.startswith('domains:'):
        flt = self.flt_and(flt, self.searchdomain({'$exists': True}))
        level = (int(field[8:]) - 1)
        field = 'hostnames.domains'
        aggrflt = {'field': re.compile(('^([^\\.]+\\.){%d}[^\\.]+$' % level))}
    elif field.startswith('cert.'):
        subfield = field[5:]
        field = ('ports.scripts.ssl-cert.' + subfield)
    elif (field == 'sshkey.bits'):
        flt = self.flt_and(flt, self.searchsshkey())
        specialproj = {'ports.scripts.ssh-hostkey.type': 1, 'ports.scripts.ssh-hostkey.bits': 1}
        specialflt = [{'$project': {'_id': 0, 'ports.scripts.ssh-hostkey.bits': {'$concat': ['$ports.scripts.ssh-hostkey.type', '###', '$ports.scripts.ssh-hostkey.bits']}}}]
        field = 'ports.scripts.ssh-hostkey.bits'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple(x['_id'].split('###'))})
    elif field.startswith('sshkey.'):
        flt = self.flt_and(flt, self.searchsshkey())
        subfield = field[7:]
        field = ('ports.scripts.ssh-hostkey.' + subfield)
    elif (field == 'ike.vendor_ids'):
        flt = self.flt_and(flt, self.searchscript(name='ike-info'))
        specialproj = {'ports.scripts.ike-info.vendor_ids.value': 1, 'ports.scripts.ike-info.vendor_ids.name': 1}
        specialflt = [{'$project': {'_id': 0, 'ports.scripts.ike-info.vendor_ids': {'$concat': ['$ports.scripts.ike-info.vendor_ids.value', '###', {'$ifNull': ['$ports.scripts.ike-info.vendor_ids.name', '']}]}}}]
        field = 'ports.scripts.ike-info.vendor_ids'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple((null_if_empty(val) for val in x['_id'].split('###')))})
    elif (field == 'ike.transforms'):
        flt = self.flt_and(flt, self.searchscript(name='ike-info', values={'transforms': {'$exists': True}}))
        specialproj = {'ports.scripts.ike-info.transforms.Authentication': 1, 'ports.scripts.ike-info.transforms.Encryption': 1, 'ports.scripts.ike-info.transforms.GroupDesc': 1, 'ports.scripts.ike-info.transforms.Hash': 1, 'ports.scripts.ike-info.transforms.LifeDuration': 1, 'ports.scripts.ike-info.transforms.LifeType': 1}
        specialflt = [{'$project': {'_id': 0, 'ports.scripts.ike-info.transforms': {'$concat': [{'$ifNull': ['$ports.scripts.ike-info.transforms.Authentication', '']}, '###', {'$ifNull': ['$ports.scripts.ike-info.transforms.Encryption', '']}, '###', {'$ifNull': ['$ports.scripts.ike-info.transforms.GroupDesc', '']}, '###', {'$ifNull': ['$ports.scripts.ike-info.transforms.Hash', '']}, '###', {'$toLower': '$ports.scripts.ike-info.transforms.LifeDuration'}, '###', {'$ifNull': ['$ports.scripts.ike-info.transforms.LifeType', '']}]}}}]
        field = 'ports.scripts.ike-info.transforms'
        outputproc = (lambda x: {'count': x['count'], '_id': tuple((null_if_empty(val) for val in x['_id'].split('###')))})
    elif (field == 'ike.notification'):
        flt = self.flt_and(flt, self.searchscript(name='ike-info', values={'notification_type': {'$exists': True}}))
        field = 'ports.scripts.ike-info.notification_type'
    elif field.startswith('ike.'):
        flt = self.flt_and(flt, self.searchscript(name='ike-info'))
        field = ('ports.scripts.ike-info.' + field[4:])
    elif field.startswith('modbus.'):
        flt = self.flt_and(flt, self.searchscript(name='modbus-discover'))
        subfield = field[7:]
        field = ('ports.scripts.modbus-discover.' + subfield)
    elif field.startswith('s7.'):
        flt = self.flt_and(flt, self.searchscript(name='s7-info'))
        subfield = field[3:]
        field = ('ports.scripts.s7-info.' + subfield)
    elif field.startswith('enip.'):
        flt = self.flt_and(flt, self.searchscript(name='enip-info'))
        subfield = field[5:]
        subfield = {'vendor': 'Vendor', 'product': 'Product    Name', 'serial': 'Serial    Number', 'devtype': 'Device    Type', 'prodcode': 'Product    Code', 'rev': 'Revision', 'ip': 'Device    IP'}.get(subfield, subfield)
        field = ('ports.scripts.enip-info.' + subfield)
    elif field.startswith('mongo.dbs.'):
        flt = self.flt_and(flt, self.searchscript(name='mongodb-databases'))
        field = ('ports.scripts.mongodb-databases.' + field[10:])
    elif field.startswith('vulns.'):
        flt = self.flt_and(flt, self.searchvuln())
        subfield = field[6:]
        if (subfield == 'id'):
            field = 'ports.scripts.vulns.id'
        else:
            field = ('ports.scripts.vulns.' + subfield)
            specialproj = {'_id': 0, 'ports.scripts.vulns.id': 1, field: 1}
            specialflt = [{'$project': {'_id': 0, field: {'$concat': ['$ports.scripts.vulns.id', '###', ('$' + field)]}}}]
            outputproc = (lambda x: {'count': x['count'], '_id': tuple(x['_id'].split('###', 1))})
    elif ((field == 'file') or (field.startswith('file') and (field[4] in '.:'))):
        if field.startswith('file:'):
            scripts = field[5:]
            if ('.' in scripts):
                (scripts, field) = scripts.split('.', 1)
            else:
                field = 'filename'
            scripts = scripts.split(',')
        else:
            field = (field[5:] or 'filename')
            scripts = None
        flt = self.flt_and(flt, self.searchfile(scripts=scripts))
        field = ('ports.scripts.ls.volumes.files.%s' % field)
        if (scripts is not None):
            specialproj = {'_id': 0, field: 1, 'ports.scripts.id': 1}
            specialflt = [{'$match': {'ports.scripts.id': flt['ports.scripts']['$elemMatch']['id']}}, {'$project': {field: {'$ifNull': [('$' + field), '']}}}]
        else:
            specialflt = [{'$project': {field: {'$ifNull': [('$' + field), '']}}}]
        outputproc = (lambda x: {'count': x['count'], '_id': (x['_id'] if x['_id'] else None)})
    elif (field == 'screenwords'):
        field = 'ports.screenwords'
        flt = self.flt_and(flt, self.searchscreenshot(words=True))
    elif (field == 'hop'):
        field = 'traces.hops.ipaddr'
        outputproc = (lambda x: {'count': x['count'], '_id': utils.int2ip(x['_id'])})
    elif (field.startswith('hop') and (field[3] in ':>')):
        specialproj = {'_id': 0, 'traces.hops.ipaddr': 1, 'traces.hops.ttl': 1}
        specialflt = [{'$match': {'traces.hops.ttl': (int(field[4:]) if (field[3] == ':') else {'$gt': int(field[4:])})}}, {'$project': {'traces.hops.ipaddr': 1}}]
        field = 'traces.hops.ipaddr'
        outputproc = (lambda x: {'count': x['count'], '_id': utils.int2ip(x['_id'])})
    pipeline = self._topvalues(field, flt=flt, topnbr=topnbr, sort=sort, limit=limit, skip=skip, least=least, aggrflt=aggrflt, specialproj=specialproj, specialflt=specialflt)
    cursor = self.set_limits(self.db[(self.colname_oldhosts if archive else self.colname_hosts)].aggregate(pipeline, cursor={}))
    if (outputproc is not None):
        return (outputproc(res) for res in cursor)
    return cursor
