'`category1` and `category2` must be categories (provided as str or
unicode objects)
Returns a generator of tuples:
({\'addr\': address, \'proto\': protocol, \'port\': port}, value)
Where `address` is an integer (use `utils.int2ip` to get the
corresponding string), and value is:
- -1  if the port is open in category1 and not in category2,
-  0  if the port is open in both category1 and category2,
-  1  if the port is open in category2 and not in category1.
This can be useful to compare open ports from two scan results
against the same targets.'

def diff_categories(self, category1, category2, flt=None, archive=False, include_both_open=True):

    category_filter = self.searchcategory([category1, category2])
    pipeline = [{'$match': (category_filter if (flt is None) else self.flt_and(flt, category_filter))}, {'$unwind': '$categories'}, {'$match': category_filter}, {'$unwind': '$ports'}, {'$match': {'ports.state_state': 'open'}}, {'$project': {'_id': 0, 'addr': 1, 'ports.protocol': 1, 'ports.port': 1, 'categories': 1}}, {'$group': {'_id': {'addr': '$addr', 'proto': '$ports.protocol', 'port': '$ports.port'}, 'categories': {'$push': '$categories'}}}]
    cursor = self.db[(self.colname_oldhosts if archive else self.colname_hosts)].aggregate(pipeline, cursor={})
    def categories_to_val(categories):
        (state1, state2) = ((category1 in categories), (category2 in categories))
        return ((state2 > state1) - (state2 < state1))
    cursor = (dict(x['_id'], value=categories_to_val(x['categories'])) for x in cursor)
    if include_both_open:
        return cursor
    else:
        return (result for result in cursor if result['value'])
