上下文:
我试图建立一个体系结构,显示POI,可以在不同的已知位置随着时间的推移。
我有两个系列,
波伊斯
{
_id: ObjectId,
name: string
}
地点
_id: ObjectId,
point: {
type: 'Point',
coordinates: Array<number>
},
poi: ObjectId // Reference to Poi
用例:
我试着建立一个查询
- 在输入中采用中心坐标+半径
- 并返回半径范围内的匹配Pois
- 仅显示最近的位置
- 按距离排序
理想情况下,具有以下输出:
[
{
_id: ObjectId(AE54232),
name: 'Some poi',
location: {
_id: ObjectId(BFE5423),
point: {
type: 'Point',
coordinates: [3, 50]
},
distance: 3
}
}
]
尝试
仔细阅读文档后,我使用了以下组合:
// Keep only locations 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
以不稳定和非确定性的顺序出现!
我试着一个接一个地评论每一步,显然这是导致" Shuffle "的$first
。这是令人惊讶的,因为docs声明:
$geoNear
按从指定点最近到最远的顺序输出文档。
$first
返回对一组文档中的第一个文档应用表达式所得到的值。仅当文档按定义的顺序时才有意义。
修复尝试
我的想法是$first
需要实际的$sort
,而不是隐式的$geoNear
排序;所以我试着在中间插入一个$sort
,就像这样:
{
$sort: {
'distance': 1,
},
},
中间是这样:
$geoNear
$sort(distance)
〈==此处$first(by poi)
$lookup(poi)
$unwind(poi)
$replaceRoot(poi { location })
但它给了我完全相同的结果!
唯一起作用的是像这样在最后添加一个$sort
{
$sort: {
'location.distance': 1,
},
},
$geoNear
- x1米20英寸1x
$lookup(poi)
$unwind(poi)
$replaceRoot(poi { location })
$sort(location.distance)
〈==此处
但我担心它在大型数据集上可能会出现性能问题
问题
有什么方法可以实现这个逻辑吗
- filter $geoNear(保持距离)
- $按引用文档分组,仅保留"最近的"
而不丢失$geoNear订单?
2条答案
按热度按时间q7solyqu1#
为了扩展@尼姆罗德serok的公认答案
如果每个poi可以有几个位置,则将它们分组可能会更改顺序,因此分组后的文档不再按距离排序
我添加了一个关于“为什么”的解释(太长了,无法评论)。
声明
在
poi
上的$geoNear
和$group
($first
)不一定会导致按距离排序的poi
。原因很简单,但MongoDb doc对此却有点说不清楚:
$first
返回对一组文档中的第一个文档应用表达式所得到的值。仅当文档按定义的顺序排列时才有意义。
这并不意味着“组的顺序将保持一致”;这意味着每个组的
$first
的属性将是一致的,只有当它在input中排序时。关键在文档页面中间的“备注”中:
尽管$sort阶段将已排序的文档作为输入传递到$group和$setWindowFields阶段,但不保证这些阶段在其自己的输出中保持排序顺序。
这基本上意味着对于
$first
分辨率,输入的顺序是受尊重的;但是组本身的顺序不一致。示例案例
假设这是$geoNear的结果
$group($first(poi))
保证 * 位置1* 将被保留并且 * 位置3* 将被丢弃;但是不保证位置1 将在位置2* 之前输出。以下结果是合法的:
这是天性使然。
zpjtge222#
如果每个
poi
可以有几个货位,那么分组可能会改变顺序,分组后的单据不再按distance
排序,可以通过分组后按distance
排序来解决: