Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Revise support for geoNear commands and $near query criteria

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...
commit 6637851b55ef81587739f8ecae92778e94d68da2 1 parent eabc12d
Jeremy Mikola jmikola authored
70 lib/Doctrine/MongoDB/Query/Builder.php
View
@@ -354,20 +354,6 @@ public function selectSlice($fieldName, $skip, $limit = null)
}
/**
- * 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.
*
* @param string $field
@@ -560,6 +546,62 @@ public function mod($mod)
}
/**
+ * 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.
*
* @param string $x1
10 lib/Doctrine/MongoDB/Query/Expr.php
View
@@ -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) {
9 lib/Doctrine/MongoDB/Query/Query.php
View
@@ -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']);
46 tests/Doctrine/MongoDB/Tests/Query/BuilderTest.php
View
@@ -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()
@@ -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()
37 tests/Doctrine/MongoDB/Tests/Query/QueryTest.php
View
@@ -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
*/
Please sign in to comment.
Something went wrong with that request. Please try again.