在 motorengine 中执行近查询的 mongoengine.GeoPointField 等效于什么?
What is the equivalent of mongoengine.GeoPointField in motorengine to perform near queries?
我有以下型号:
class DbObjectWithCoordinates(Document):
coordinates = GeoPointField() # this used to work with mongengine
我使用 mongoengine.GeoPointField
执行查询,例如查找给定坐标附近的所有对象:
user_coordinates = user.coordinates
objects_of_interest = DbObjectWithCoordinates.objects(coordinates__near=user_coordinates, coordinaes_max_distance=3)
但是 GeoPointField
字段在 motorengine 中不可用。
是否可以通过 motorengine 定义对象并使用这样的查询?如果没有,是否有针对此类用例的解决方法?
我认为实现地理点字段相当容易。下面是非常简单的实现,当然它不是完整的。
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
但您需要确保在地理查询之前正确更新了发动机操作员。
from motorengine.query_builder.transform import OPERATORS
OPERATORS.update({
"near": GeoNearOperator,
"around": GeoSphearNearOperator,
"search": TextSearch
})
我有以下型号:
class DbObjectWithCoordinates(Document):
coordinates = GeoPointField() # this used to work with mongengine
我使用 mongoengine.GeoPointField
执行查询,例如查找给定坐标附近的所有对象:
user_coordinates = user.coordinates
objects_of_interest = DbObjectWithCoordinates.objects(coordinates__near=user_coordinates, coordinaes_max_distance=3)
但是 GeoPointField
字段在 motorengine 中不可用。
是否可以通过 motorengine 定义对象并使用这样的查询?如果没有,是否有针对此类用例的解决方法?
我认为实现地理点字段相当容易。下面是非常简单的实现,当然它不是完整的。
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
但您需要确保在地理查询之前正确更新了发动机操作员。
from motorengine.query_builder.transform import OPERATORS
OPERATORS.update({
"near": GeoNearOperator,
"around": GeoSphearNearOperator,
"search": TextSearch
})