使用 Doctrine MongoDB ODM 进行地理空间查询

Posted

技术标签:

【中文标题】使用 Doctrine MongoDB ODM 进行地理空间查询【英文标题】:Geo spatial queries with Doctrine MongoDB ODM 【发布时间】:2012-06-17 11:49:16 【问题描述】:

我的文档的坐标属性上有一个二维索引。使用 mongo shell,我可以像这样查询集合;

db.adverts.find(coordinates:$near:[20,40])

如预期的那样返回以下结果;

 "_id" : ObjectId("4fddac51352de93903000000"), "title" : "dummy #3", "coordinates" :  "longitude" : 22, "latitude" : 31  
 "_id" : ObjectId("4fddac48352de95105000000"), "title" : "dummy #3", "coordinates" :  "longitude" : 20, "latitude" : 30  
 "_id" : ObjectId("4fddaca4352de93703000000"), "title" : "dummy #3", "coordinates" :  "longitude" : 31, "latitude" : 22  
 "_id" : ObjectId("4fdda6a2352de90a03000000"), "title" : "dummy title", "created" : ISODate("2012-06-17T09:42:58Z"), "coordinates" :  "longitude" : 54.1234, "latitude" : -1.234  
 "_id" : ObjectId("4fdda6d8352de9c004000000"), "title" : "dummy title #2", "created" : ISODate("2012-06-17T09:43:52Z"), "coordinates" :  "longitude" : 54.34, "latitude" : -1.124  

但是,根据文档使用 Doctrine 查询完全相同的集合,我没有得到任何结果,例如

$adverts = $dm->createQueryBuilder('Advert')
                      ->field('coordinates')->near(20, 40)
                      ->getQuery()
                      ->execute();
$adverts->count(); // => 0

我的广告 yaml 看起来像这样;

Advert:
    type: document
    collection: adverts
    fields:
        id:
            id: true
        title:
            type: string
        content:
            type: string
        created:
            type: date
        updated:
            type: date
        status:
            type: int
        distance:
            type: int

    indexes:
        coordinates:
            keys:
                coordinates: 2d

    referenceOne:
        owner:
            targetDocument: User

    embedOne:
        coordinates:
            targetDocument: Coordinates

而坐标文件是这样的;

Coordinates:
    type: embeddedDocument
    fields:
        longitude:
            type: float
        latitude:
            type: float

任何想法为什么使用 Doctrine 的 ODM 会在同一查询上返回零结果?

更新 #1 看起来 Doctrine\MongoDB\Query\Builder::near() L363 有问题。方法参数忽略第二个值 ($y)。所以只有第一个值被传递执行。

【问题讨论】:

这可能是一个愚蠢的问题,但不应将坐标定义为 Advert.yaml 中的字段,因为它毕竟是 -a field-。或者这就是 EmbedOne 的目的。 getQuery() 返回什么?另外,请注意 MongoDB 希望坐标字段中的顺序为:纬度、经度。它确实关心字段的名称。 Derick - getQuery() 返回一个 Doctrine\ODM\MongoDB\Query\Query 的实例。 Geoist - embedOne 指定坐标属性 【参考方案1】:

near() 方法似乎存在实现问题(请参阅https://github.com/doctrine/mongodb/pull/53)。要修复我的原始查询,我需要执行以下操作;

$adverts = $dm->createQueryBuilder('Advert')
              ->field('coordinates.latitude')->near(20)
              ->field('coordinates.longitude')->near(40);

$adverts->getQuery()->count(); // => 5

这与当前的文档相矛盾,该文档暗示 x、y 坐标都可以传递给 Doctrine\MongoDB\Query\Builder::near()。

编辑

为了让生活更轻松,我创建了一个自定义存储库类来为这种不一致提供更直观的解决方案;

public function near($longitude, $latitude)

    $query = $this->createQueryBuilder()
                  ->field('coordinates.longitude')->near((float) $longitude)
                  ->field('coordinates.latitude')->near((float) $latitude)
                  ->getQuery();

    return $query;

【讨论】:

以上是关于使用 Doctrine MongoDB ODM 进行地理空间查询的主要内容,如果未能解决你的问题,请参考以下文章

Doctrine MongoDB 在没有 ODM 的情况下使用

Doctrine MongoDB 在没有 ODM 的情况下使用

Doctrine ODM with MongoDB 需要两个参考映射集

使用 Doctrine MongoDB ODM 进行地理空间查询

通过 mongodb/doctrine2 odm 中的嵌套引用值查询

Doctrine 2 ODM MongoDB 从内存中将图像存储在 GridFS 中