Skip to content
This repository has been archived by the owner on Nov 11, 2020. It is now read-only.

Commit

Permalink
Revise support for geoNear commands and $near query criteria
Browse files Browse the repository at this point in the history
Fixes #47. Previously, the near() builder method was used to support the geoNear command instead of $near query criteria. This was unintuitive, given how other geo methods like withinBox() operated.

Instead, we add a new geoNear() builder method, which operates similarly to mapReduce() and switches the query into GEO_LOCATION mode. We also add methods to specify the distanceMultipler and maxDistance options.

The near() builder method is repurposed to define $near query criteria for a field or expression.
  • Loading branch information
jmikola committed Jul 12, 2012
1 parent eabc12d commit 6637851
Show file tree
Hide file tree
Showing 5 changed files with 142 additions and 30 deletions.
70 changes: 56 additions & 14 deletions lib/Doctrine/MongoDB/Query/Builder.php
Original file line number Diff line number Diff line change
Expand Up @@ -353,20 +353,6 @@ public function selectSlice($fieldName, $skip, $limit = null)
return $this;
}

/**
* Add where near criteria.
*
* @param string $x
* @param string $y
* @return Builder
*/
public function near($value)
{
$this->query['type'] = Query::TYPE_GEO_LOCATION;
$this->query['near'][$this->currentField] = $value;
return $this;
}

/**
* Set the current field to operate on.
*
Expand Down Expand Up @@ -559,6 +545,62 @@ public function mod($mod)
return $this;
}

/**
* Specify a geoNear command for this query.
*
* This method sets the "near" option for the geoNear command. The "num"
* option may be set using limit(). The "distanceMultiplier" and
* "maxDistance" options may be set using their respective builder methods.
* Additional query criteria will be assigned to the "query" option.
*
* @param string $x
* @param string $y
* @return Builder
*/
public function geoNear($x, $y)
{
$this->query['type'] = Query::TYPE_GEO_LOCATION;
$this->query['geoNear'] = array('near' => array($x, $y));
return $this;
}

/**
* Set the "distanceMultiplier" option for a geoNear command query.
*
* @param string $distanceMultiplier
* @return Builder
*/
public function distanceMultiplier($distanceMultiplier)
{
$this->query['geoNear']['distanceMultiplier'] = $distanceMultiplier;
return $this;
}

/**
* Set the "maxDistance" option for a geoNear command query.
*
* @param string $maxDistance
* @return Builder
*/
public function maxDistance($maxDistance)
{
$this->query['geoNear']['maxDistance'] = $maxDistance;
return $this;
}

/**
* Add where $near query.
*
* @param string $x
* @param string $y
* @return Builder
*/
public function near($x, $y)
{
$this->expr->near($x, $y);
return $this;
}

/**
* Add where $within $box query.
*
Expand Down
10 changes: 10 additions & 0 deletions lib/Doctrine/MongoDB/Query/Expr.php
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,16 @@ public function mod($mod)
return $this->operator($this->cmd . 'mod', $mod);
}

public function near($x, $y)
{
if ($this->currentField) {
$this->query[$this->currentField][$this->cmd . 'near'] = array($x, $y);
} else {
$this->query[$this->cmd . 'near'] = array($x, $y);
}
return $this;
}

public function withinBox($x1, $y1, $x2, $y2)
{
if ($this->currentField) {
Expand Down
9 changes: 8 additions & 1 deletion lib/Doctrine/MongoDB/Query/Query.php
Original file line number Diff line number Diff line change
Expand Up @@ -213,7 +213,14 @@ public function execute()
if (isset($this->query['limit']) && $this->query['limit']) {
$this->options['num'] = $this->query['limit'];
}
return $this->collection->near($this->query['near'], $this->query['query'], $this->options);

foreach (array('distanceMultiplier', 'maxDistance') as $key) {
if (isset($this->query['geoNear'][$key]) && $this->query['geoNear'][$key]) {
$this->options[$key] = $this->query['geoNear'][$key];
}
}

return $this->collection->near($this->query['geoNear']['near'], $this->query['query'], $this->options);

case self::TYPE_COUNT:
return $this->collection->count($this->query['query']);
Expand Down
46 changes: 31 additions & 15 deletions tests/Doctrine/MongoDB/Tests/Query/BuilderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,6 @@ public function testFindAndUpdateQuery()
$this->assertNull($query->execute());
}

public function testGeoLocationQuery()
{
$qb = $this->getTestQueryBuilder()
->field('x')->near(1)
->field('y')->near(2)
->field('username')->equals('jwage');

$this->assertEquals(Query::TYPE_GEO_LOCATION, $qb->getType());
$expected = array(
'username' => 'jwage'
);
$this->assertEquals($expected, $qb->getQueryArray());
$this->assertInstanceOf('Doctrine\MongoDB\ArrayIterator', $qb->getQuery()->execute());
}

public function testGroupQuery()
{
$qb = $this->getTestQueryBuilder()
Expand Down Expand Up @@ -366,6 +351,37 @@ public function testDeepClone()
$this->assertCount(1, $qb->getQueryArray());
}

public function testGeoNearQuery()
{
$qb = $this->getTestQueryBuilder()
->geoNear(50, 50)
->distanceMultiplier(2.5)
->maxDistance(5)
->field('type')->equals('restaurant')
->limit(10);

$this->assertEquals(Query::TYPE_GEO_LOCATION, $qb->getType());

$expectedQuery = array('type' => 'restaurant');
$this->assertEquals($expectedQuery, $qb->getQueryArray());

$geoNear = $qb->debug('geoNear');
$this->assertEquals(array(50, 50), $geoNear['near']);
$this->assertEquals(2.5, $geoNear['distanceMultiplier']);
$this->assertEquals(5, $geoNear['maxDistance']);
$this->assertEquals(10, $qb->debug('limit'));
$this->assertInstanceOf('Doctrine\MongoDB\ArrayIterator', $qb->getQuery()->execute());
}

public function testNear()
{
$qb = $this->getTestQueryBuilder()
->field('loc')->near(50, 50);

$expected = array('loc' => array('$near' => array(50, 50)));
$this->assertEquals($expected, $qb->getQueryArray());
}

public function testWithinBox()
{
$qb = $this->getTestQueryBuilder()
Expand Down
37 changes: 37 additions & 0 deletions tests/Doctrine/MongoDB/Tests/Query/QueryTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,43 @@ public function testMapReduceOptionsArePassed()
$query->execute();
}

public function testGeoNearOptionsArePassed()
{
$collection = $this->getMockCollection();

$queryArray = array(
'type' => Query::TYPE_GEO_LOCATION,
'geoNear' => array(
'near' => array(50, 50),
'distanceMultiplier' => 2.5,
'maxDistance' => 5,
),
'limit' => 10,
'query' => array('altitude' => array('$gt' => 1)),
);

$query = new Query(
$this->getMockDatabase(),
$collection,
$queryArray,
array(),
''
);

$collection->expects($this->any())
->method('geoNear')
->with(array(50, 50),
array('altitude' => array('$gt' => 1)),
$this->logicalAnd(
new ArrayHasValueUnderKey('distanceMultiplier', 2.5),
new ArrayHasValueUnderKey('maxDistance', 5),
new ArrayHasValueUnderKey('num', 10)
)
);

$query->execute();
}

/**
* @return \Doctrine\MongoDB\Collection
*/
Expand Down

0 comments on commit 6637851

Please sign in to comment.