Mongoose Geo Near Search - 如何在给定距离内排序?
Mongoose Geo Near Search - How to sort within a given distance?
我正在使用 mongoose 和带有 maxDistance 的近距离查询来过滤靠近给定 gps 位置的元素。但是,near 查询会覆盖其他排序。我想要的是在给定点的 maxDistance 范围内找到所有元素,然后按其他属性排序。
这是我目前正在做的一个例子:
架构:
mongoose.Schema({
name: {
type: String,
required: true
},
score: {
type: Number,
required: true,
default: 0
},
location: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number]
}
},
....
});
查询:
model.find({
"location.coordinates": {
"$near": {
"$maxDistance": 1000,
"$geometry": {
"type": "Point",
"coordinates": [
10,
10
]
}
}
}
}).sort('-score');
在 find 之后添加一个 .sort 在这里没有帮助,并且项目返回的顺序是 near。
$near
按距离对文档进行排序,这在这里是一种浪费。使用不对文档进行排序的 $geoWithin
可能更好。类似于:
model.find({
"location.coordinates": {
$geoWithin: { $center: [ [-74, 40.74], <radius> ] } } }
).sort({score: -1});
$center
文档有更多详细信息。
在查找查询中您需要使用 location
而不是 location.coordinates
。
router.get("/test", async (req, res) => {
const lat = 59.9165591;
const lng = 10.7881978;
const maxDistanceInMeters = 1000;
const result = await model
.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [lng, lat],
},
$maxDistance: maxDistanceInMeters,
},
},
})
.sort("-score");
res.send(result);
});
要使 $near 工作,您需要相关集合的 2dsphere 索引:
db.collection.createIndex( { "location" : "2dsphere" } )
在 mongodb $near 文档中说:
$near sorts documents by distance. If you also include a sort() for
the query, sort() re-orders the matching documents, effectively
overriding the sort operation already performed by $near. When using
sort() with geospatial queries, consider using $geoWithin operator,
which does not sort documents, instead of $near.
由于您对按距离排序不感兴趣,正如 Nic 指出不需要使用 $near,最好像这样使用 $geoWithin:
router.get("/test", async (req, res) => {
const lat = 59.9165591;
const lng = 10.7881978;
const distanceInKilometer = 1;
const radius = distanceInKilometer / 6378.1;
const result = await model
.find({
location: { $geoWithin: { $centerSphere: [[lng, lat], radius] } },
})
.sort("-score");
res.send(result);
});
为了计算半径,我们将公里除以 6378.1,将英里除以 3963.2,如所述 here。
所以这将找到 1 公里半径内的位置。
示例文档:
[
{
"location": {
"type": "Point",
"coordinates": [
10.7741692,
59.9262198
]
},
"score": 50,
"_id": "5ea9d4391e468428c8e8f505",
"name": "Name1"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7736078,
59.9246991
]
},
"score": 70,
"_id": "5ea9d45c1e468428c8e8f506",
"name": "Name2"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7635027,
59.9297932
]
},
"score": 30,
"_id": "5ea9d47b1e468428c8e8f507",
"name": "Name3"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7635027,
59.9297932
]
},
"score": 40,
"_id": "5ea9d4971e468428c8e8f508",
"name": "Name4"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7768093,
59.9287668
]
},
"score": 90,
"_id": "5ea9d4bd1e468428c8e8f509",
"name": "Name5"
},
{
"location": {
"type": "Point",
"coordinates": [
10.795769,
59.9190384
]
},
"score": 60,
"_id": "5ea9d4e71e468428c8e8f50a",
"name": "Name6"
},
{
"location": {
"type": "Point",
"coordinates": [
10.1715157,
59.741873
]
},
"score": 110,
"_id": "5ea9d7d216bdf8336094aa92",
"name": "Name7"
}
]
输出:(1km以内,按分数降序排列)
[
{
"location": {
"type": "Point",
"coordinates": [
10.7768093,
59.9287668
]
},
"score": 90,
"_id": "5ea9d4bd1e468428c8e8f509",
"name": "Name5"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7736078,
59.9246991
]
},
"score": 70,
"_id": "5ea9d45c1e468428c8e8f506",
"name": "Name2"
},
{
"location": {
"type": "Point",
"coordinates": [
10.795769,
59.9190384
]
},
"score": 60,
"_id": "5ea9d4e71e468428c8e8f50a",
"name": "Name6"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7741692,
59.9262198
]
},
"score": 50,
"_id": "5ea9d4391e468428c8e8f505",
"name": "Name1"
}
]
我正在使用 mongoose 和带有 maxDistance 的近距离查询来过滤靠近给定 gps 位置的元素。但是,near 查询会覆盖其他排序。我想要的是在给定点的 maxDistance 范围内找到所有元素,然后按其他属性排序。 这是我目前正在做的一个例子:
架构:
mongoose.Schema({
name: {
type: String,
required: true
},
score: {
type: Number,
required: true,
default: 0
},
location: {
type: {
type: String,
default: 'Point',
},
coordinates: {
type: [Number]
}
},
....
});
查询:
model.find({
"location.coordinates": {
"$near": {
"$maxDistance": 1000,
"$geometry": {
"type": "Point",
"coordinates": [
10,
10
]
}
}
}
}).sort('-score');
在 find 之后添加一个 .sort 在这里没有帮助,并且项目返回的顺序是 near。
$near
按距离对文档进行排序,这在这里是一种浪费。使用不对文档进行排序的 $geoWithin
可能更好。类似于:
model.find({
"location.coordinates": {
$geoWithin: { $center: [ [-74, 40.74], <radius> ] } } }
).sort({score: -1});
$center
文档有更多详细信息。
在查找查询中您需要使用 location
而不是 location.coordinates
。
router.get("/test", async (req, res) => {
const lat = 59.9165591;
const lng = 10.7881978;
const maxDistanceInMeters = 1000;
const result = await model
.find({
location: {
$near: {
$geometry: {
type: "Point",
coordinates: [lng, lat],
},
$maxDistance: maxDistanceInMeters,
},
},
})
.sort("-score");
res.send(result);
});
要使 $near 工作,您需要相关集合的 2dsphere 索引:
db.collection.createIndex( { "location" : "2dsphere" } )
在 mongodb $near 文档中说:
$near sorts documents by distance. If you also include a sort() for the query, sort() re-orders the matching documents, effectively overriding the sort operation already performed by $near. When using sort() with geospatial queries, consider using $geoWithin operator, which does not sort documents, instead of $near.
由于您对按距离排序不感兴趣,正如 Nic 指出不需要使用 $near,最好像这样使用 $geoWithin:
router.get("/test", async (req, res) => {
const lat = 59.9165591;
const lng = 10.7881978;
const distanceInKilometer = 1;
const radius = distanceInKilometer / 6378.1;
const result = await model
.find({
location: { $geoWithin: { $centerSphere: [[lng, lat], radius] } },
})
.sort("-score");
res.send(result);
});
为了计算半径,我们将公里除以 6378.1,将英里除以 3963.2,如所述 here。
所以这将找到 1 公里半径内的位置。
示例文档:
[
{
"location": {
"type": "Point",
"coordinates": [
10.7741692,
59.9262198
]
},
"score": 50,
"_id": "5ea9d4391e468428c8e8f505",
"name": "Name1"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7736078,
59.9246991
]
},
"score": 70,
"_id": "5ea9d45c1e468428c8e8f506",
"name": "Name2"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7635027,
59.9297932
]
},
"score": 30,
"_id": "5ea9d47b1e468428c8e8f507",
"name": "Name3"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7635027,
59.9297932
]
},
"score": 40,
"_id": "5ea9d4971e468428c8e8f508",
"name": "Name4"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7768093,
59.9287668
]
},
"score": 90,
"_id": "5ea9d4bd1e468428c8e8f509",
"name": "Name5"
},
{
"location": {
"type": "Point",
"coordinates": [
10.795769,
59.9190384
]
},
"score": 60,
"_id": "5ea9d4e71e468428c8e8f50a",
"name": "Name6"
},
{
"location": {
"type": "Point",
"coordinates": [
10.1715157,
59.741873
]
},
"score": 110,
"_id": "5ea9d7d216bdf8336094aa92",
"name": "Name7"
}
]
输出:(1km以内,按分数降序排列)
[
{
"location": {
"type": "Point",
"coordinates": [
10.7768093,
59.9287668
]
},
"score": 90,
"_id": "5ea9d4bd1e468428c8e8f509",
"name": "Name5"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7736078,
59.9246991
]
},
"score": 70,
"_id": "5ea9d45c1e468428c8e8f506",
"name": "Name2"
},
{
"location": {
"type": "Point",
"coordinates": [
10.795769,
59.9190384
]
},
"score": 60,
"_id": "5ea9d4e71e468428c8e8f50a",
"name": "Name6"
},
{
"location": {
"type": "Point",
"coordinates": [
10.7741692,
59.9262198
]
},
"score": 50,
"_id": "5ea9d4391e468428c8e8f505",
"name": "Name1"
}
]