Question

I'm trying to use GeoSpatial features of MongoDB. I have this Document:

<?php

namespace My\CoreBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;

/**
 * @MongoDB\Document
 * @MongoDB\Index(keys={"coordinates"="2d"})
 */
class WorkoutLocation
{
    /** @MongoDB\Id */
    protected $id;

    /** @MongoDB\ReferenceMany(targetDocument="User") */
    protected $users;

    /** @MongoDB\String */
    protected $name;

    /** @MongoDB\EmbedOne(targetDocument="Coordinates") */
    protected $coordinates;

    /** @MongoDB\Distance */
    protected $distance;

    public function __construct()
    {
        $this->users = new \Doctrine\Common\Collections\ArrayCollection();
    }

    public function getId()
    {
        return $this->id;
    }

    public function addUser(\My\CoreBundle\Document\User $users)
    {
        $this->users[] = $users;
    }

    public function removeUser(\My\CoreBundle\Document\User $users)
    {
        $this->users->removeElement($users);
    }

    public function getUsers()
    {
        return $this->users;
    }

    public function setName($name)
    {
        $this->name = $name;
        return $this;
    }

    public function getName()
    {
        return $this->name;
    }

    /**
     * Set coordinates
     *
     * @param My\CoreBundle\Document\Coordinates $coordinates
     * @return \WorkoutLocation
     */
    public function setCoordinates(\My\CoreBundle\Document\Coordinates $coordinates)
    {
        $this->coordinates = $coordinates;
        return $this;
    }

    public function getCoordinates()
    {
        return $this->coordinates;
    }

    /**
     * Set distance
     *
     * @param string $distance
     * @return \WorkoutLocation
     */
    public function setDistance($distance)
    {
        $this->distance = $distance;
        return $this;
    }

    /**
     * Get distance
     *
     * @return string $distance
     */
    public function getDistance()
    {
        return $this->distance;
    }
}

and Coordinates document

<?php

namespace My\CoreBundle\Document;

use Doctrine\ODM\MongoDB\Mapping\Annotations as MongoDB;

/** @MongoDB\EmbeddedDocument */
class Coordinates
{
    /** @MongoDB\Float */
    protected $latitude;

    /** @MongoDB\Float */
    protected $longitude;

    public function __construct($latitude = 0.0, $longitude = 0.0)
    {
        $this->setLatitude($latitude);
        $this->setLongitude($longitude);
    }

    /**
     * Set latitude
     *
     * @param float $latitude
     * @return \Coordinates
     */
    public function setLatitude($latitude)
    {
        $this->latitude = $latitude;
        return $this;
    }

    /**
     * Get latitude
     *
     * @return float $latitude
     */
    public function getLatitude()
    {
        return $this->latitude;
    }

    /**
     * Set longitude
     *
     * @param float $longitude
     * @return \Coordinates
     */
    public function setLongitude($longitude)
    {
        $this->longitude = $longitude;
        return $this;
    }

    /**
     * Get longitude
     *
     * @return float $longitude
     */
    public function getLongitude()
    {
        return $this->longitude;
    }
}

And i have this data

/* 0 */
{
  "_id" : ObjectId("517a1f45dd1854c818000001"),
  "name" : "ABC Gym Master",
  "coordinates" : {
    "latitude" : -8.711741,
    "longitude" : 115.166538
  }
}

/* 1 */
{
  "_id" : ObjectId("517a1f45dd1854c818000002"),
  "name" : "DEF Master Gym",
  "coordinates" : {
    "latitude" : -8.712292,
    "longitude" : 115.16694
  }
}

/* 2 */
{
  "_id" : ObjectId("517a1f45dd1854c818000003"),
  "name" : "GHI Master Gym",
  "coordinates" : {
    "latitude" : -8.68808,
    "longitude" : 115.1718
  }
}

View:

{% for location in locations %}
Name: {{ location.name }}, Distance: {{ location.distance }}
{% endfor %}

But when I try this code:

$dm = $this->get('doctrine_mongodb')->getManager();

$locations = $dm->createQueryBuilder('MyCoreBundle:WorkoutLocation')
        ->field('coordinates')->near(-8.688038,115.171329)
        ->getQuery()
        ->execute();
return $this->render('MyCoreBundle:Default:geospatial.html.twig', array('locations' => $locations));

It returns error:

An exception has been thrown during the rendering of a template ("localhost:27017: can't find any special indices: 2d (needs index), 2dsphere (needs index), for: { coordinates: { $near: [ -8.688038000000001, 115.171329 ] } }") in MyCoreBundle:Default:geospatial.html.twig at line 1. 

What am I missing?

Was it helpful?

Solution 2

Have you updated your indexes?

When you create an index (via annotations or via an external mapping file), remember to run the command that will actually create the index and an empty collection on your db:

app/console doctrine:mongodb:schema:update

Be sure to run it also on your production db.


To be sure your indexes are there:

run in the Mongo shell:

db.WorkoutLocation.stats();

OTHER TIPS

You can use geospacial queries only on fields that are indexed proper way. Try creating one field (say, location), which is array containing just longitude and latitude (not as key/value, just two plain values), and add 2d or 2dsphere index to it.

http://docs.mongodb.org/manual/core/geospatial-indexes/

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top