Uploaded image for project: 'PHP ORMs'
  1. PHP ORMs
  2. PHPORM-155

Create PipelineBuilder using Query\Builder::aggregate()

    • Type: Icon: Task Task
    • Resolution: Fixed
    • Priority: Icon: Unknown Unknown
    • laravel-4.3.0
    • Affects Version/s: None
    • Component/s: Laravel
    • None
    • PHP Drivers

      Detailed Design (Laravel ORM)

      Builder

      The builder interface supports adding stages to a pipeline and then returning that pipeline once it’s complete:

      interface PipelineBuilder

       

      {
          // Factory to start out with an existing pipeline and append to it
          public static function fromPipeline(Pipeline|PipelineBuilder $pipeline): static;
       
          public function addFields(...$fields): static;
          public function match(...$fields): static;
          public function sort(...$specification): static;
          public function limit(int $limit): static;
       
          public function getPipeline(): Pipeline;
      }
      

       

      The builder can be used to assemble aggregation pipelines without starting from a model. The resulting Pipeline instance can then be converted to an array (for usage in the Collection::aggregate method) or used further. The following example shows how to create an example pipeline:

       

      // $oneMonthAgo is initialised to today - 1 month
      $pipeline = $builder
          ->match(status: 'enabled', createdAt: gte($oneMonthAgo))
          ->addFields(
              filteredList: filter(
                  input: arrayFieldPath(items'),
                  cond: eq(variable('this.status'), 'enabled'),
              ),
          )
          ->sort(createdAt: -1)
          ->limit(5)
          ->getPipeline();
      

       

      Model integration

      The main entry point for aggregation is through the Model class in Laravel, which is extended by every database model class. The main entry point is an aggregate method that takes a pipeline and returns a Laravel Collection instance with the results:

       

      interface SupportsAggregation
      {
          public function aggregate(array|Pipeline $pipeline, array $options): Collection;
      }
       
      

       

       

      // Usage
      $allResults = MyModel::aggregate($builder);
      

       

      Due to aggregate already being present in Laravel, the actual implementation will have to also accept a string parameter. In that case, we defer to the existing implementation of aggregate instead of running an aggregation pipeline.

      Choosing result class

      By default the results of an aggregation pipeline are returned using the default type map of the underlying client object. However, users can choose to have their results hydrated into a model class of their choosing. In the builder, the asModel() method can be used to change the output model:

       

      MyModel
          ::aggregate(pipeline(...))
          ->asModel(AggregatedMyModel::class)
      

       

          ->first();

      This instructs the builder to return results as instances of the AggregatedMyModel class, allowing for further processing. Since these models will not be mapped to an existing document in the database, any Active Record functionality must be disabled (i.e. save() should not actually try to persist changes to the database).

            Assignee:
            jerome.tamarelle@mongodb.com Jérôme Tamarelle
            Reporter:
            jerome.tamarelle@mongodb.com Jérôme Tamarelle
            Votes:
            0 Vote for this issue
            Watchers:
            2 Start watching this issue

              Created:
              Updated:
              Resolved: