上下文:
我正试图建立一个展示POI的架构,随着时间的推移,POI可以位于不同的已知位置.
我有两个Collection ,
POIS
{
_id: ObjectId,
name: string
}
位置
_id: ObjectId,
point: {
type: 'Point',
coordinates: Array<number>
},
poi: ObjectId // Reference to Poi
使用 case :
所以我正在try 构建一个查询,该查询
- 采用中心坐标+半径作为输入
- 并返回小于半径范围内的匹配POI
- 只有他们最近的位置
- 按距离排序
理想情况下,具有以下输出:
[
{
_id: ObjectId(AE54232),
name: 'Some poi',
location: {
_id: ObjectId(BFE5423),
point: {
type: 'Point',
coordinates: [3, 50]
},
distance: 3
}
}
]
try
仔细阅读文档时,我使用了这样的组合:
// Keep only 位置 within radius,
// output 'distance'
// and sort by distance
{
$geoNear: {
near: nearCenter,
key: 'point',
distanceField: 'distance',
maxDistance: nearRadius,
spherical: true,
},
},
// Keep only first (assumed 'nearest')
// location of each poi
{
$group: {
_id: '$poi',
location: {
$first: '$$ROOT'
}
}
},
// Retrieve poi
{
$lookup: {
from: 'POIS',
localField: '_id',
foreignField: '_id',
as: 'poi',
},
},
// Flatten poi
{
$unwind: {
path: '$poi',
},
},
// Push poi at the root,
// and put location inside 'location'
{
$replaceRoot: {
newRoot: {
$mergeObjects: [
"$poi",
{ location: "$location" },
]
},
}
},
因此,总结如下:
-
$geoNear
个个个 -
$first(by poi)
个个个 -
$lookup(poi)
个个个 -
$unwind(poi)
个个个 -
$replaceRoot(poi { location })
个个个
麻烦
我面临着一种奇怪的行为,查询基本上是工作的;除了它不是按距离排序:poi
和location
的顺序是不稳定的和不确定的!
我试着逐一 comments 每一步,显然这就是导致"洗牌"的$first
步.这很令人惊讶,因为doctor 说:
输出距指定点最近到最远的文档in order.
返回将表达式应用于一组文档组中的第一个文档所产生的值.只有当文档are in a defined order时才有意义.
修复try
我认为$first
应该是实际的$sort
,而不是隐式的$geoNear
个个个排序;所以我try 在两者之间插入$sort
,如下所示:
{
$sort: {
'distance': 1,
},
},
中间是这样的:
-
$geoNear
个个个 -
$sort(distance)
lt;==此处 -
$first(by poi)
个个个 -
$lookup(poi)
个个个 -
$unwind(poi)
个个个 -
$replaceRoot(poi { location })
个个个
但它给了我完全相同的结果!
唯一起作用的就是在最后加$sort
,就像这样
{
$sort: {
'location.distance': 1,
},
},
-
$geoNear
个个个 -
$first(by poi)
个个个 -
$lookup(poi)
个个个 -
$unwind(poi)
个个个 -
$replaceRoot(poi { location })
个个个 -
$sort(location.distance)
lt;==此处
但我担心它在大型数据集上可能会有性能问题
问题
有什么方法可以实现这一逻辑吗
- 过滤器$GeoNear(保持距离)
- $GROUP BY REFERED DOCUMENT,仅保留‘最近的’
而不会失go $GeoNear订单?