code: def _prepare_aggregate(cls, *args, **kw):
  		
  		
  		stages = []
  		stage_args = []
  		fragments = []
  		
  		for arg in args:  # Split the positional arguments into filter fragments and projection stages.
  			(fragments if isinstance(arg, Filter) else stage_args).append(arg)
  		
  		cls, collection, query, options = cls._prepare_query(
  				cls.AGGREGATE_MAPPING,
  				cls.AGGREGATE_OPTIONS,
  				*fragments,
  				**kw
  			)
  		
  		if query:
  			stages.append({'$match': query})
  		
  		stages.extend(stage_args)
  		
  		if 'sort' in options:  # Convert the find-like option to a stage with the correct semantics.
  			stages.append({'$sort': odict(options.pop('sort'))})
  		
  		if 'skip' in options:  # Note: Sort + limit memory optimization invalidated when skipping.
  			stages.append({'$skip': options.pop('skip')})
  		
  		if 'limit' in options:
  			stages.append({'$limit': options.pop('limit')})
  		
  		if 'projection' in options:
  			stages.append({'$project': options.pop('projection')})
  		
  		return cls, collection, stages, options
docs: Generate and execute an aggregate query pipline using combined plain and parametric query generation.
  		
  		Additionally, performs argument case normalization, refer to the `_prepare_query` method's docstring.
  		
  		This provides a find-like interface for generating aggregate pipelines with a few shortcuts that make
  		aggregates behave more like "find, optionally with more steps". Positional arguments that are not Filter
  		instances are assumed to be aggregate pipeline stages.
  		
  		https://api.mongodb.com/python/current/api/pymongo/collection.html#pymongo.collection.Collection.aggregate