Commit 3f86eb8b authored by Jens Segers's avatar Jens Segers Committed by GitHub

Merge pull request #1208 from benargo/geospatial-support

Add direct geospatial index support
parents 3276bac2 fa0c1c6e
......@@ -234,10 +234,32 @@ Supported operations are:
- hasCollection
- index and dropIndex (compound indexes supported as well)
- unique
- background, sparse, expire (MongoDB specific)
- background, sparse, expire, geospatial (MongoDB specific)
All other (unsupported) operations are implemented as dummy pass-through methods, because MongoDB does not use a predefined schema. Read more about the schema builder on http://laravel.com/docs/schema
### Geospatial indexes
Geospatial indexes are handy for querying location-based documents. They come in two forms: `2d` and `2dsphere`. Use the schema builder to add these to a collection.
To add a `2d` index:
```php
Schema::create('users', function($collection)
{
$collection->geospatial('name', '2d');
});
```
To add a `2dsphere` index:
```php
Schema::create('users', function($collection)
{
$collection->geospatial('name', '2dsphere');
});
```
Extensions
----------
......@@ -274,7 +296,7 @@ If you want to use MongoDB to handle failed jobs, change the database in `config
],
```
And add the service provider in `config/app.php`:
And add the service provider in `config/app.php`:
```php
Jenssegers\Mongodb\MongodbQueueServiceProvider::class,
......@@ -525,6 +547,72 @@ Performs a modulo operation on the value of a field and selects documents with a
User::where('age', 'mod', [10, 0])->get();
```
**Near**
**NOTE:** Specify coordinates in this order: `longitude, latitude`.
```php
$users = User::where('location', 'near', [
'$geometry' => [
'type' => 'Point',
'coordinates' => [
-0.1367563,
51.5100913,
],
],
'$maxDistance' => 50,
]);
```
**GeoWithin**
```php
$users = User::where('location', 'geoWithin', [
'$geometry' => [
'type' => 'Polygon',
'coordinates' => [[
[
-0.1450383,
51.5069158,
],
[
-0.1367563,
51.5100913,
],
[
-0.1270247,
51.5013233,
],
[
-0.1450383,
51.5069158,
],
]],
],
]);
```
**GeoIntersects**
```php
$locations = Location::where('location', 'geoIntersects', [
'$geometry' => [
'type' => 'LineString',
'coordinates' => [
[
-0.144044,
51.515215,
],
[
-0.129545,
51.507864,
],
],
],
]);
```
**Where**
Matches documents that satisfy a JavaScript expression. For more information check http://docs.mongodb.org/manual/reference/operator/query/where/#op._S_where
......
......@@ -144,6 +144,31 @@ class Blueprint extends \Illuminate\Database\Schema\Blueprint
return $this;
}
/**
* Specify a geospatial index for the collection.
*
* @param string|array $columns
* @param string $index
* @param array $options
* @return Blueprint
*/
public function geospatial($columns = null, $index = '2d', $options = [])
{
if ($index == '2d' or $index == '2dsphere') {
$columns = $this->fluent($columns);
$columns = array_flip($columns);
foreach ($columns as $column => $value) {
$columns[$column] = $index;
}
$this->index($columns, null, null, $options);
}
return $this;
}
/**
* Specify the number of seconds after wich a document should be considered expired based,
* on the given single-field index containing a date.
......
<?php
class GeospatialTest extends TestCase
{
public function setUp()
{
parent::setUp();
Schema::collection('locations', function ($collection) {
$collection->geospatial('location', '2dsphere');
});
Location::create([
'name' => 'Picadilly',
'location' => [
'type' => 'LineString',
'coordinates' => [
[
-0.1450383,
51.5069158,
],
[
-0.1367563,
51.5100913,
],
[
-0.1304123,
51.5112908,
],
],
],
]);
Location::create([
'name' => 'StJamesPalace',
'location' => [
'type' => 'Point',
'coordinates' => [
-0.139827,
51.504736,
],
],
]);
}
public function tearDown()
{
Schema::drop('locations');
}
public function testGeoWithin()
{
$locations = Location::where('location', 'geoWithin', [
'$geometry' => [
'type' => 'Polygon',
'coordinates' => [[
[
-0.1450383,
51.5069158,
],
[
-0.1367563,
51.5100913,
],
[
-0.1270247,
51.5013233,
],
[
-0.1460866,
51.4952136,
],
[
-0.1450383,
51.5069158,
],
]],
],
]);
$this->assertEquals(1, $locations->count());
$locations->get()->each(function ($item, $key) {
$this->assertEquals('StJamesPalace', $item->name);
});
}
public function testGeoIntersects()
{
$locations = Location::where('location', 'geoIntersects', [
'$geometry' => [
'type' => 'LineString',
'coordinates' => [
[
-0.144044,
51.515215,
],
[
-0.1367563,
51.5100913,
],
[
-0.129545,
51.5078646,
],
],
]
]);
$this->assertEquals(1, $locations->count());
$locations->get()->each(function ($item, $key) {
$this->assertEquals('Picadilly', $item->name);
});
}
public function testNear()
{
$locations = Location::where('location', 'near', [
'$geometry' => [
'type' => 'Point',
'coordinates' => [
-0.1367563,
51.5100913,
],
],
'$maxDistance' => 50,
]);
$locations = $locations->get();
$this->assertEquals(1, $locations->count());
$locations->each(function ($item, $key) {
$this->assertEquals('Picadilly', $item->name);
});
}
}
......@@ -167,6 +167,24 @@ class SchemaTest extends TestCase
$this->assertEquals(1, $index['key']['token']);
}
public function testGeospatial()
{
Schema::collection('newcollection', function ($collection) {
$collection->geospatial('point');
$collection->geospatial('area', '2d');
$collection->geospatial('continent', '2dsphere');
});
$index = $this->getIndex('newcollection', 'point');
$this->assertEquals('2d', $index['key']['point']);
$index = $this->getIndex('newcollection', 'area');
$this->assertEquals('2d', $index['key']['area']);
$index = $this->getIndex('newcollection', 'continent');
$this->assertEquals('2dsphere', $index['key']['continent']);
}
public function testDummies()
{
Schema::collection('newcollection', function ($collection) {
......
<?php
use Jenssegers\Mongodb\Eloquent\Model as Eloquent;
class Location extends Eloquent
{
protected $collection = 'locations';
protected static $unguarded = true;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment