def aggregate(self, pipeline, **kwargs):
        pipeline_operators = [
            '$project',
            '$match',
            '$redact',
            '$limit',
            '$skip',
            '$unwind',
            '$group',
            '$sort',
            '$geoNear',
            '$out']
        group_operators = [
            '$addToSet',
            '$first',
            '$last',
            '$max',
            '$min',
            '$avg',
            '$push',
            '$sum']
        boolean_operators = ['$and', '$or', '$not']  # noqa
        set_operators = [  # noqa
            '$setEquals',
            '$setIntersection',
            '$setDifference',
            '$setUnion',
            '$setIsSubset',
            '$anyElementTrue',
            '$allElementsTrue']
        compairison_operators = [  # noqa
            '$cmp',
            '$eq',
            '$gt',
            '$gte',
            '$lt',
            '$lte',
            '$ne']
        aritmetic_operators = [  # noqa
            '$add',
            '$divide',
            '$mod',
            '$multiply',
            '$subtract']
        string_operators = [  # noqa
            '$concat',
            '$strcasecmp',
            '$substr',
            '$toLower',
            '$toUpper']
        text_search_operators = ['$meta']  # noqa
        array_operators = ['$size']  # noqa
        projection_operators = ['$map', '$let', '$literal']  # noqa
        date_operators = [  # noqa
            '$dayOfYear',
            '$dayOfMonth',
            '$dayOfWeek',
            '$year',
            '$month',
            '$week',
            '$hour',
            '$minute',
            '$second',
            '$millisecond']
        conditional_operators = ['$cond', '$ifNull']  # noqa

        out_collection = [doc for doc in self.find()]
        grouped_collection = []
        for expression in pipeline:
            for k, v in iteritems(expression):
                if k == '$match':
                    out_collection = [doc for doc in out_collection
                                      if filter_applies(v, doc)]
                elif k == '$group':
                    _id = expression['$group']['_id']
                    group_func_keys = self._get_group_id_fields(_id)

                    out_collection, group_func_keys = self._add_group_id_fields(out_collection,
                                                                                group_func_keys)

                    out_collection = sorted(out_collection, key=itemgetter(*group_func_keys))
                    for field, value in iteritems(v):
                        if field != '_id':
                            for func, key in iteritems(value):
                                if func == "$sum" or "$avg":
                                    grouped = itertools.groupby(out_collection,
                                                                itemgetter(*group_func_keys))

                                    for ret_value, group in grouped:
                                        group_list = ([x for x in group])
                                        ret_value = ret_value if isinstance(ret_value, tuple)\
                                            else [ret_value]
                                        doc_id = {k: v for (k, v) in zip(_id.keys(), ret_value)}\
                                            if isinstance(_id, dict) else ret_value[0]

                                        doc_dict = {'_id': doc_id}

                                        new_doc = True
                                        for doc in grouped_collection:
                                            if doc['_id'] == doc_id:
                                                doc_dict = doc
                                                new_doc = False
                                                break

                                        current_val = doc_dict.get(field, 0)
                                        from_field = key.replace('$', '')
                                        if func == "$sum":
                                            for doc in group_list:
                                                current_val = sum([current_val,
                                                                   doc.get(from_field, 0)])
                                            doc_dict[field] = current_val
                                        elif func == "$avg":
                                            for doc in group_list:
                                                current_val = sum([current_val,
                                                                   doc.get(from_field, 0)])
                                            current_avg = current_val / max(len(group_list), 1)
                                            doc_dict[field] = current_avg

                                        if new_doc:
                                            grouped_collection.append(doc_dict)
                                else:
                                    if func in group_operators:
                                        raise NotImplementedError(
                                            "Although %s is a valid group operator for the "
                                            "aggregation pipeline, %s is currently not implemented "
                                            "in Mongomock." % func)
                                    else:
                                        raise NotImplementedError(
                                            "%s is not a valid group operator for the aggregation "
                                            "pipeline. See http://docs.mongodb.org/manual/meta/"
                                            "aggregation-quick-reference/ for a complete list of "
                                            "valid operators." % func)
                    out_collection = grouped_collection
                elif k == '$sort':
                    sort_array = []
                    for x, y in v.items():
                        sort_array.append({x: y})
                    for sort_pair in reversed(sort_array):
                        for sortKey, sortDirection in sort_pair.items():
                            out_collection = sorted(
                                out_collection,
                                key=lambda x: _resolve_sort_key(sortKey, x),
                                reverse=sortDirection < 0)
                elif k == '$skip':
                    out_collection = out_collection[v:]
                elif k == '$limit':
                    out_collection = out_collection[:v]
                elif k == '$unwind':
                    if not isinstance(v, helpers.basestring) and v[0] != '$':
                        raise ValueError(
                            "$unwind failed: exception: field path references must be prefixed "
                            "with a '$' '%s'" % v)
                    if len(v.split('.')) > 1:
                        raise NotImplementedError(
                            "Mongmock does not currently support nested field paths in the $unwind "
                            "implementation. '%s'" % v)
                    unwound_collection = []
                    for doc in out_collection:
                        array_value = doc.get(v[1:])
                        if array_value in (None, []):
                            continue
                        elif not isinstance(array_value, list):
                            raise TypeError(
                                '$unwind must specify an array field, field: '
                                '"%s", value found: %s' % (v, array_value))
                        for field_item in array_value:
                            unwound_collection.append(copy.deepcopy(doc))
                            unwound_collection[-1][v[1:]] = field_item
                    out_collection = unwound_collection
                else:
                    if k in pipeline_operators:
                        raise NotImplementedError(
                            "Although '%s' is a valid operator for the aggregation pipeline, it is "
                            "currently not implemented in Mongomock." % k)
                    else:
                        raise NotImplementedError(
                            "%s is not a valid operator for the aggregation pipeline. "
                            "See http://docs.mongodb.org/manual/meta/aggregation-quick-reference/ "
                            "for a complete list of valid operators." % k)
        return CommandCursor(out_collection)
dataset/ETHPy150Open vmalloc/mongomock/mongomock/collection.py/Collection.aggregate/original