我一直在尝试使用 NestJS 和 Mongoose 解决地理空间查询。我已经做了很多尝试,现在我什至记不清所有的尝试,但现在我的代码如下所示:
// application.module.ts
@Module({
imports: [
MongooseModule.forRoot('mongodb://localhost/<DATABASE_NAME>', {
useCreateIndex: true,
useNewUrlParser: true,
useUnifiedTopology: true
}
]
})
// restaurants.schema.ts
import { v4 } from 'uuid';
import { Schema } from 'mongoose';
const RestaurantsSchema = new Schema({
_id: {
type: String,
default: v4
},
name: {
type: String,
required: true
},
location: {
type: {
type: String,
enum: ['Point'],
default: 'Point',
required: true
},
coordinates: {
type: [Number],
required: true,
index: '2dsphere'
}
}
}, {
timestamps: true
});
export { RestaurantsSchema };
我用
restaurants
在 restaurantModel: Model<IRestaurant>
集合中插入了一些记录。然后,当我从 mongo 聚合时,我得到结果:
> db.restaurants.getIndexes()
[
{
"v" : 2,
"key" : {
"_id" : 1
},
"name" : "_id_",
"ns" : "<DATABASE_NAME>.restaurants"
},
{
"v" : 2,
"key" : {
"location.coordinates" : "2dsphere"
},
"name" : "location.coordinates_2dsphere",
"ns" : "<DATABASE_NAME>.restaurants",
"background" : true,
"2dsphereIndexVersion" : 3
}
]
> db.restaurants.aggregate([{ $geoNear: { near: { type: "Point", coordinates: [-46.6954844,-23.5006969] }, distanceField: "distanceFromMe", maxDistance: 1000 * 1609.34, distanceMultiplier: 1 / 1609.34, spherical: true } }]).pretty()
{
"_id" : "011deea3-415b-45d9-90dd-097e9f689a2b",
"location" : {
"type" : "Point",
"coordinates" : [
-46.6954844,
-23.6006969
]
},
"name" : "Dona So",
"createdAt" : ISODate("2020-02-28T02:40:28.493Z"),
"updatedAt" : ISODate("2020-02-28T02:40:28.493Z"),
"__v" : 0,
"distanceFromMe" : 6.917049537167114
}
看起来工作正常。但是,当我尝试对 Mongoose 做同样的事情时:
// restaurants.repository.ts
public async getNear(longitude: Number, latitude: Number, maxDistance: Number): Promise<IRestaurantModel[]> {
const restaurants = await this.restaurantModel.aggregate([
{
$geoNear: {
near: {
type: 'Point',
coordinates: [longitude, latitude]
},
distanceField: 'distanceFromMe',
maxDistance: 1000 * 1609.34,
distanceMultiplier: 1 / 1609.34,
spherical: true,
}
}
]);
return restaurants;
}
输出:
ok: 0,
errmsg: 'Failed to determine whether query system can provide a covered ' +
'projection :: caused by :: geo near accepts just one argument when ' +
'querying for a GeoJSON point. Extra field found: $maxDistance: ' +
'1609340.0',
code: 2,
codeName: 'BadValue',
name: 'MongoError',
[Symbol(mongoErrorContextSymbol)]: {}
现在我什至不知道错误到底在哪里。我还尝试使用猫鼬的
aggregate().near()
。
我正在使用的一些版本:
您可能看过这个或类似的指南:https://www.slingacademy.com/article/how-to-use-geolocation-in-mongoose-with-examples/ 。 虽然正确,但它添加了一些嵌套,如果没有必要,您不必使用它们。 您可以在任何内部有两个数字且索引为 '2d' 的字段上使用 $near。 我将 NestJs 与猫鼬一起使用,以下对我有用:
架构定义:
@Schema({ timestamps: true })
export class ClassName extends Document {
@Prop({ required: [true, 'In Schema: Title is required!'] })
title: string;
@Prop({ required: [true, 'In Schema: Coordinates are required!'], index: '2d' })
coordinates: number[];
};
export const SchemaName = SchemaFactory.createForClass(ClassName);
查询:
const queryOptions = {
coordinates: {
$near: [-75 , 32], // lat & lng must be in reverse for query
$maxDistance: 1000, // in meters
},
};
await this.modelName.find(queryOptions);
这将查找坐标在 1000 米范围内的条目。结果按从最接近到最远的顺序排序。