Skip to content

Commit

Permalink
Use aggregations for pagination, fixes mongodb#437 and mongodb#428
Browse files Browse the repository at this point in the history
  • Loading branch information
jenssegers committed Mar 28, 2015
1 parent 9d04822 commit 9603949
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 33 deletions.
55 changes: 41 additions & 14 deletions src/Jenssegers/Mongodb/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ class Builder extends BaseBuilder {
*/
public $timeout;

/**
* Indicate if we are executing a pagination query.
*
* @var bool
*/
public $paginating = false;

/**
* All of the available clause operators.
*
Expand Down Expand Up @@ -140,7 +147,7 @@ public function getFresh($columns = array())
$wheres = $this->compileWheres();

// Use MongoDB's aggregation framework when using grouping or aggregation functions.
if ($this->groups or $this->aggregate)
if ($this->groups or $this->aggregate or $this->paginating)
{
$group = array();

Expand All @@ -155,12 +162,14 @@ public function getFresh($columns = array())
// this mimics MySQL's behaviour a bit.
$group[$column] = array('$last' => '$' . $column);
}
}
else
{
// If we don't use grouping, set the _id to null to prepare the pipeline for
// other aggregation functions.
$group['_id'] = null;

// Do the same for other columns that are selected.
foreach ($this->columns as $column)
{
$key = str_replace('.', '_', $column);

$group[$key] = array('$last' => '$' . $column);
}
}

// Add aggregation functions to the $group part of the aggregation pipeline,
Expand All @@ -184,22 +193,26 @@ public function getFresh($columns = array())
}
}

// If no aggregation functions are used, we add the additional select columns
// to the pipeline here, aggregating them by $last.
else
// When using pagination, we limit the number of returned columns
// by adding a projection.
if ($this->paginating)
{
foreach ($this->columns as $column)
{
$key = str_replace('.', '_', $column);

$group[$key] = array('$last' => '$' . $column);
$this->projections[$column] = 1;
}
}

// The _id field is mandatory when using grouping.
if ($group and empty($group['_id']))
{
$group['_id'] = null;
}

// Build the aggregation pipeline.
$pipeline = array();
if ($wheres) $pipeline[] = array('$match' => $wheres);
$pipeline[] = array('$group' => $group);
if ($group) $pipeline[] = array('$group' => $group);

// Apply order and limit
if ($this->orders) $pipeline[] = array('$sort' => $this->orders);
Expand Down Expand Up @@ -370,6 +383,20 @@ public function whereBetween($column, array $values, $boolean = 'and', $not = fa
return $this;
}

/**
* Set the limit and offset for a given page.
*
* @param int $page
* @param int $perPage
* @return \Illuminate\Database\Query\Builder|static
*/
public function forPage($page, $perPage = 15)
{
$this->paginating = true;

return $this->skip(($page - 1) * $perPage)->take($perPage);
}

/**
* Insert a new record into the database.
*
Expand Down
21 changes: 6 additions & 15 deletions tests/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ class QueryTest extends TestCase {
public function setUp()
{
parent::setUp();

// only run this stuff once
if (self::$started) return;

User::create(array('name' => 'John Doe', 'age' => 35, 'title' => 'admin'));
User::create(array('name' => 'Jane Doe', 'age' => 33, 'title' => 'admin'));
User::create(array('name' => 'Harry Hoe', 'age' => 13, 'title' => 'user'));
Expand All @@ -20,8 +16,12 @@ public function setUp()
User::create(array('name' => 'Tommy Toe', 'age' => 33, 'title' => 'user'));
User::create(array('name' => 'Yvonne Yoe', 'age' => 35, 'title' => 'admin'));
User::create(array('name' => 'Error', 'age' => null, 'title' => null));
}

self::$started = true;
public function tearDown()
{
User::truncate();
parent::tearDown();
}

public function testWhere()
Expand Down Expand Up @@ -311,16 +311,7 @@ public function testPaginate()
$this->assertEquals(2, $results->count());
$this->assertNull($results->first()->title);
$this->assertEquals(9, $results->total());
}

/*
* FIXME: This should be done in tearDownAfterClass, but something doens't work:
* https://travis-ci.org/duxet/laravel-mongodb/jobs/46657530
*/
public function testTruncate()
{
User::truncate();
$this->assertEquals(0, User::count());
$this->assertEquals(1, $results->currentPage());
}

}
4 changes: 0 additions & 4 deletions tests/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,9 @@ protected function getEnvironmentSetUp($app)
// reset base path to point to our package's src directory
//$app['path.base'] = __DIR__ . '/../src';

// load custom config
$config = require 'config/database.php';

// set mongodb as default connection
$app['config']->set('database.default', 'mongodb');

// overwrite database configuration
$app['config']->set('database.connections.mysql', $config['connections']['mysql']);
$app['config']->set('database.connections.mongodb', $config['connections']['mongodb']);

Expand Down

0 comments on commit 9603949

Please sign in to comment.