我正在寻找一个正确的数据库,它支持基于位置的搜索,发现MongoDB支持GeoJSON对象。
这是一个Store应用程序,在这个应用程序中,用户可以四处查看并选择靠近他的Store来订购产品。
简单供应商模式:
const VendorSchema = new Schema({
address: {
type: String,
required: [true, 'Please add address']
},
formattedAddress: {
type: String
},
location: {
type: {
type: String,
enum: ['Point']
},
// GeoJSON Points
coordinates: {
type: [Number],
index: '2dsphere'
},
formattedAddress: String,
street: String,
city: String,
state: String,
zipcode: String,
country: String
},
createdAt: {
type: Date,
default: Date.now
}
});数据库中将有许多FMCG产品可供多个供应商销售。
产品模式:
const ProductSchema = new Schema({
name: {
type: String,
required: true
},
desc: {
type: String,
required: true
},
price: Number,
createdAt: {
type: Date,
default: Date.now
}
});一个供应商可以销售多个产品,一个产品可以被许多供应商出售,供应商和产品之间存在着
N-to-N关系。
创建一个新模式的想法也是如此,VendorProduct Schema :
const VendorProductSchema = new Schema({
price: Number,
discountVal: Number,
vendor : {
type: ObjectId,
ref: 'Vendor'
},
createdAt: {
type: Date,
default: Date.now
}
});--这是它变得棘手/具有挑战性的地方:
Vendor/Stores用户可以查找其周围的
,也可以直接搜索Product。
如果被要求找到供应商,它会在供应商集合中直接查找--在一定的半径内。
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})但是,当用户搜索产品时:
系统应该返回搜索产品的详细信息和附近的销售商-从最近到最远,在一定的半径。
为此,我考虑在GeoJSON模式中存储供应商的产品的VendorProduct位置详细信息。
VendorProduct模式与GeoJSON详细信息:
const VendorProductSchema = new Schema({
price: Number,
discountVal: Number,
vendor : {
type: ObjectId,
ref: 'Vendor'
},
location: {
type: {
type: String,
enum: ['Point']
},
// GeoJSON Points
coordinates: {
type: [Number],
index: '2dsphere'
}
},
createdAt: {
type: Date,
default: Date.now
}
});假设用户使用关键字洋葱进行搜索。它将发现在产品收集,将使用ProductID和在转过滤他们在VendorProducts集合的基础上的地理协调。以这种方式,我可以从产品信息,如描述,图像从产品收集&供应商,价格信息从VendorProducts收集。
这只是要记住,一个单一的产品可以由多个供应商出售。当用户使用产品名称进行搜索时,可能会有N个不同价格的卖家。但是,为了找到最接近的供应商,我们正在考虑在VendorProductSchema中存储供应商的位置细节。
几个问题:
中,这种地理位置搜索的时间复杂度是多少?
发布于 2020-05-18 14:46:17
根据我的理解,您应该只在供应商模式中保存位置坐标,因为它们与供应商相关。旧的VendorProduct模式很好
Case1:用户正在寻找附近的供应商
您需要运行一个查询,以便根据用户的位置查找供应商,并向用户提供供应商列表
为此,你需要跑
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})Case2:用户正在寻找他/她可以在附近找到的产品
在这种情况下,还可以先通过上面的查询搜索附近的供应商(记住,如果不需要减少搜索半径,附近的供应商将受到限制)。
一旦您得到了附近的所有供应商,将他们的it保存在一个数组中,让我们调用它
vendorArray = [vendor_id1, vendor_id2.....]然后在VendorProduct模式中搜索产品
VendorProduct.find({
vendor : {
$in: vendorArray
}
})以上解决方案只是为了替代在VendorProductSchema中存储位置信息。
现在您需要在从vendorProduct集合中获取产品in之后获取产品详细信息,我建议您应该在vendorProduct中添加产品名称或任何其他要搜索或筛选的字段。
当前方法的缺点在VendorProduct中存储位置坐标的缺点很少
您要在多个集合中保存冗余数据,并且要维护这些数据,而添加/编辑/删除records
中对几千条记录运行geojson查询比在VendorProduct中运行100条记录更有效。
发布于 2020-05-10 13:25:18
我只知道基本的MongoDB,但我注意到您正在VendorProduct集合中存储位置数据。在这种情况下,如果供应商编辑他们的坐标,那么需要更新多个文档。
相反,您可以将位置保留在供应商集合本身中。在查询时,您可以执行嵌套查询来获取给定名称的产品,其中供应商的坐标值小于x,y。
https://docs.mongodb.com/manual/tutorial/query-embedded-documents/
发布于 2020-05-15 13:18:46
是的,我看不出为什么不。MongoDB支持geoJSON,并允许以多种方式轻松查询这些信息。
如果我理解你的处境:
用户可以查找其周围的供应商/商店,也可以直接搜索产品。由于基于位置的服务系统应该发送围绕用户的产品,因此考虑将供应商的GeoJSON位置详细信息存储在VendorProduct模式中,以便系统只能够使用供应商的详细信息查询围绕用户的产品。
给定一个特定点(用户位置),在给定半径内查找有可用产品的供应商。
由于产品可以有多个供应商,而且供应商位于位置,因此没有理由重复供应商的位置。如果您确实将供应商位置信息存储在两个地方,比如供应商和产品,那么您的应用程序就不再有一个真理了。试图保持这些文档的同步变得非常混乱。如果您想分离任何内容,我将将供应商的位置分隔到独立索引集合(下面示例中的vendorGEO),并调整当前的供应商文档以指向这个新集合。这样,您可以查询哪些供应商在用户附近,然后抓取供应商,然后只提取所需的供应商,并搜索他们的产品。
下面是一个mongo示例,它根据点的半径(圆)(用户位置)查找所有未排序的位置。
db.vendorGEO.createIndex({location: "2dsphere"})
db.vendorGEO.find({location: {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})英里: 1/3963.2弧度公里: 1/6378.15弧度
官方文件:https://docs.mongodb.com/manual/reference/operator/query/centerSphere/index.html
你可以用多边形代替。如果你有一个预先定义的区域,比如在城市范围内,多边形会更有用:
一个多边形,它需要四个点,和最初的起点。注意使用嵌套数组设置坐标的方式:
db.collection.find({location: {$geoWithin: {$geometry: {type: "Polygon", coordinates: [[[point 1], [point 2], [point 3], [point 4], [point 1 again]]]}}}})若要轻松地存储多边形信息,请将它们存储在单独的集合中。
db.areas.insertOne({name: "Example Location", area: {type: "Polygon", coordinates: [[[longA, latA], [longB, latB], [longC, latC], [longD, latD], [longA, latA]]]}})若要查找某个点是否位于多边形内,请搜索多边形内的一个点,引用定义的区域字段。
db.areas.find({area: {$geoIntersects: {$geometry: {type: "Point", coordinates: [longA, latA]}}}})中的时间复杂度是多少?
当使用$geoIntersects或$geoWithin时,您不需要索引,但是增加查询速度是明智的。
对于任何时间复杂性的关注,您都可以通过使用.explain()命令更深入地研究查询规划/优化来了解幕后的情况。
https://stackoverflow.com/questions/61683097
复制相似问题