简体   繁体   English

相当于motorengine中的mongoengine.GeoPointField可以执行近距离查询?

[英]What is the equivalent of mongoengine.GeoPointField in motorengine to perform near queries?

I have the following model: class DbObjectWithCoordinates(Document): coordinates = GeoPointField() # this used to work with mongengine 我有以下模型: class DbObjectWithCoordinates(Document): coordinates = GeoPointField() # this used to work with mongengine

I used the mongoengine.GeoPointField to perform queries like find all objects near to given coordinates: 我使用mongoengine.GeoPointField执行查询,例如查找给定坐标附近的所有对象:

user_coordinates = user.coordinates
objects_of_interest = DbObjectWithCoordinates.objects(coordinates__near=user_coordinates, coordinaes_max_distance=3)

Howewer the GeoPointField field is not available in motorengine. 然而, GeoPointField字段在发动机中不可用。 Is it possible to define objects and use queries like this with motorengine? 是否可以在Motorengine中定义对象并使用类似的查询? And if not is there a workaround for this kind of use case? 如果没有,这种用例是否有解决方法?

I think it would be fairly easy to implement geopoint field. 我认为实现geopoint字段将相当容易。 Below is very simple implementation offcourse it is not a full one. 下面是非常简单的实现途径,它不是一个完整的。

from motorengine.fields import *
from pymongo import GEOSPHERE, GEO2D
from motorengine.query.base import QueryOperator
from motorengine.utils import serialize, deserialize

class GeoPointField(BaseField):

    def __init__(self, *args, **kwargs):
        super(GeoPointField, self).__init__(*args, **kwargs)

    def validate(self, lst):
        if not isinstance(lst, (list, )):
            return False
        return True

    def to_son(self, lst):
        longitude = lst[1]
        latitude = lst[0]
        value = {"type": "Point", "coordinates": [latitude, longitude]}
        return value

    def from_son(self, jsn):
        valued = jsn
        longitude = valued.get("coordinates")[1]
        latitude = valued.get("coordinates")[0]
        return [latitude, longitude]

class GeoNearOperator(QueryOperator):

    def to_query(self, field_name, value):
        return {
                field_name: {
                      "$near": {
                         "$geometry": {
                           "type": "Point",
                           "coordinates": list(value[0])
                         },
                         "$minDistance": value[1]
                      }
                   }
                }

    def get_value(self, field_name, raw_value):
        return raw_value


class GeoSphearNearOperator(QueryOperator):

    EARTH_RADIOUS = 3963.2

    def to_query(self, field_name, value):
        return {
                 field_name: {
                  "$geoWithin": {
                       "$centerSphere": [list(value[0]),
                                         value[1]/self.EARTH_RADIOUS]
                     }
                 }
               }

    def get_value(self, field_name, raw_value):
        return raw_value

class Events(MotorEngineDocument):

    __indexes__ = [('location', GEOSPHERE)]

    name = StringField(required=True)
    tid = StringField(required=True)
    event_on = DateTimeField(required=True)
    location = GeoPointField(required=True)


    @classmethod
    async def nearby(cls, lat, lon, radious, limit=10, skip=0):
        results = await cls.objects.limit(limit).skip(skip)\
            .filter(location__around=[(lat, lon), radious])\
            .find_all()
        return results

But you need to be sure that the motorengine operators are updated properly before geo query. 但是,在地理查询之前,您需要确保正确更新了发动机操作员。

from motorengine.query_builder.transform import OPERATORS
OPERATORS.update({
   "near": GeoNearOperator,
   "around": GeoSphearNearOperator,
   "search": TextSearch
})

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM