2dsphere, GeoJSON, and Doctrine MongoDB
By Jeremy Mikola, 10gen software engineer and maintainer of Doctrine MongoDB ODM. It seems that GeoJSON is all the rage these days. Last month, Ian Bentley shared a bit about the new geospatial features in MongoDB 2.4. Derick Rethans, one
By Jeremy Mikola, 10gen software engineer and maintainer of Doctrine MongoDB ODM.
It seems that GeoJSON is all the rage these days. Last month, Ian Bentley shared a bit about the new geospatial features in MongoDB 2.4. Derick Rethans, one of my PHP driver teammates and a renowned OpenStreetMap aficionado, recently blogged about importing OSM data into MongoDB as GeoJSON objects. A few days later, GitHub added support for rendering .geojson
files in repositories, using a combination of Leaflet.js, MapBox, and OpenStreetMap data. Coincidentally, I visited a local CloudCamp meetup last week to present on geospatial data, and for the past two weeks I’ve been working on adding support for MongoDB 2.4’s geospatial query operators to Doctrine MongoDB.
Doctrine MongoDB is an abstraction for the PHP driver that provides a fluent query builder API among other useful features. It’s used internally by Doctrine MongoDB ODM, but is completely usable on its own. One of the challenges in developing the library has been supporting multiple versions of MongoDB and the PHP driver. The introduction of read preferences last year is one such example. We wanted to still allow users to set slaveOk
bits for older server and driver versions, but allow read preferences to apply for newer versions, all without breaking our API and abiding by semantic versioning. Now, the setSlaveOkay()
method in Doctrine MongoDB will invoke setReadPreference()
if it exists in the driver, and fall back to the deprecated setSlaveOkay()
driver method otherwise.
Query Builder API
Before diving into the geospatial changes for Doctrine MongoDB, let’s take a quick look at the query builder API. Suppose we had a collection, test.places
, with some OpenStreetMap annotations (key=value
strings) stored in a tags
array and a loc
field containing longitude/latitude coordinates in MongoDB’s legacy point format (a float tuple) for a 2d
index. Doctrine’s API allows queries to be constructed like so:
$connection = new \Doctrine\MongoDB\Connection(); $collection = $connection->selectCollection('test', 'places'); $qb = $collection->createQueryBuilder() ->field('loc') ->near(-73.987415, 40.757113) ->maxDistance(0.00899928); ->field('tags') ->equals('amenity=restaurant'); $cursor = $qb->getQuery()->execute();
This above example executes the following query:
{ "loc": { "$near": [-73.987415, 40.757113], "$maxDistance": 0.00899928 }, "tags": "amenity=restaurant" }
This simple query will return restaurants within half a kilometer of 10gen’s NYC office at 229 West 43rd Street. If only it was so easy to find good restaurants near Times Square!
Supporting New and Old Geospatial Queries
When the new 2dsphere
index type was introduced in MongoDB 2.4, operators such $near
and $geoWithin
were changed to accept GeoJSON geometry objects in addition to their legacy point and shape arguments. $near
was particularly problematic because of its optional $maxDistance
argument. As shown above, $maxDistance
previously sat alongside $near
and was measured in radians. It now sits within $near
and is measured in meters. Using a 2dsphere
index and GeoJSON points, the same query takes on a whole new shape:
{ "loc": { "$near": { "$geometry": { "type": "Point", "coordinates" [-73.987415, 40.757113] }, "$maxDistance": 500 } }, "tags": "amenity=restaurant" }
This posed a hurdle for Doctrine MongoDB’s query builder, because we wanted to support 2dsphere
queries without drastically changing the API. Unfortunately, there was no obvious way for near()
to discern whether a pair of floats denoted a legacy or GeoJSON point, or whether a number signified radians or meters in the case of maxDistance()
. I also anticipated we might run into a similar quandry for the $geoWithin
builder method, which accepts an array of point coordinates.
Method overloading seemed preferable to creating separate builder methods or introducing a new “mode” parameter to handle 2dsphere
queries. Although PHP has no language-level support for overloading, it is commonly implemented by inspecting an argument’s type at runtime. In our case, this would necessitate having classes for GeoJSON geometries (e.g. Point, LineString, Polygon), which we could differentiate from the legacy geometry arrays.
Introducing a GeoJSON Library for PHP
A cursory search for GeoJSON PHP libraries turned up php-geojson, from the MapFish project, and geoPHP. I was pleased to see that geoPHP was available via Composer (PHP’s de facto package manager), but neither library implemented the GeoJSON spec in its entirety. This seemed like a ripe opportunity to create such a library, and so geojson was born a few days later.
At the time of this writing, 2dsphere
support for Doctrine’s query builder is still being developed; however, I envision it will take the following form when complete:
use GeoJson\Geometry\Point; // ... $qb = $collection->createQueryBuilder() ->field('loc') ->near(new Point([-73.987415, 40.757113])) ->maxDistance(0.00899928); ->field('tags') ->equals('amenity=restaurant');
All of the GeoJson classes implement JsonSerializable, one of the newer interfaces introduced in PHP 5.4, which will allow Doctrine to prepare them for MongoDB queries with a single method call. One clear benefit over the legacy geometry arrays is that the GeoJson library performs its own validation. When a Polygon is passed to geoWithin()
, Doctrine won’t have to worry about whether all of its rings are closed LineStrings; the library would catch such an error in the constructor. This helps achieve a separation of concerns, which in turn increases the maintainability of both libraries.
I look forward to finishing up 2dsphere
support for Doctrine MongoDB in the coming weeks. In the meantime, if you happen to fall in the fabled demographic of PHP developers in need of a full GeoJSON implementation, please give geojson a look and share some feedback.
原文地址:2dsphere, GeoJSON, and Doctrine MongoDB, 感谢原作者分享。

Hot AI Tools

Undresser.AI Undress
AI-powered app for creating realistic nude photos

AI Clothes Remover
Online AI tool for removing clothes from photos.

Undress AI Tool
Undress images for free

Clothoff.io
AI clothes remover

Video Face Swap
Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Article

Hot Tools

Notepad++7.3.1
Easy-to-use and free code editor

SublimeText3 Chinese version
Chinese version, very easy to use

Zend Studio 13.0.1
Powerful PHP integrated development environment

Dreamweaver CS6
Visual web development tools

SublimeText3 Mac version
God-level code editing software (SublimeText3)

Hot Topics



InnoDB's full-text search capabilities are very powerful, which can significantly improve database query efficiency and ability to process large amounts of text data. 1) InnoDB implements full-text search through inverted indexing, supporting basic and advanced search queries. 2) Use MATCH and AGAINST keywords to search, support Boolean mode and phrase search. 3) Optimization methods include using word segmentation technology, periodic rebuilding of indexes and adjusting cache size to improve performance and accuracy.

Full table scanning may be faster in MySQL than using indexes. Specific cases include: 1) the data volume is small; 2) when the query returns a large amount of data; 3) when the index column is not highly selective; 4) when the complex query. By analyzing query plans, optimizing indexes, avoiding over-index and regularly maintaining tables, you can make the best choices in practical applications.

Yes, MySQL can be installed on Windows 7, and although Microsoft has stopped supporting Windows 7, MySQL is still compatible with it. However, the following points should be noted during the installation process: Download the MySQL installer for Windows. Select the appropriate version of MySQL (community or enterprise). Select the appropriate installation directory and character set during the installation process. Set the root user password and keep it properly. Connect to the database for testing. Note the compatibility and security issues on Windows 7, and it is recommended to upgrade to a supported operating system.

The difference between clustered index and non-clustered index is: 1. Clustered index stores data rows in the index structure, which is suitable for querying by primary key and range. 2. The non-clustered index stores index key values and pointers to data rows, and is suitable for non-primary key column queries.

Article discusses popular MySQL GUI tools like MySQL Workbench and phpMyAdmin, comparing their features and suitability for beginners and advanced users.[159 characters]

Article discusses strategies for handling large datasets in MySQL, including partitioning, sharding, indexing, and query optimization.

MySQL is an open source relational database management system. 1) Create database and tables: Use the CREATEDATABASE and CREATETABLE commands. 2) Basic operations: INSERT, UPDATE, DELETE and SELECT. 3) Advanced operations: JOIN, subquery and transaction processing. 4) Debugging skills: Check syntax, data type and permissions. 5) Optimization suggestions: Use indexes, avoid SELECT* and use transactions.

MySQL supports four index types: B-Tree, Hash, Full-text, and Spatial. 1.B-Tree index is suitable for equal value search, range query and sorting. 2. Hash index is suitable for equal value searches, but does not support range query and sorting. 3. Full-text index is used for full-text search and is suitable for processing large amounts of text data. 4. Spatial index is used for geospatial data query and is suitable for GIS applications.
