首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为基于位置的服务设计MongoDB架构的最佳方法是什么?

为基于位置的服务设计MongoDB架构的最佳方法是什么?
EN

Stack Overflow用户
提问于 2020-05-08 15:58:11
回答 3查看 1.7K关注 0票数 0

我正在寻找一个正确的数据库,它支持基于位置的搜索,发现MongoDB支持GeoJSON对象。

这是一个Store应用程序,在这个应用程序中,用户可以四处查看并选择靠近他的Store来订购产品。

简单供应商模式:

代码语言:javascript
复制
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产品可供多个供应商销售。

产品模式:

代码语言:javascript
复制
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 :

代码语言:javascript
复制
const VendorProductSchema = new Schema({
    price: Number,
    discountVal: Number,
    vendor : { 
        type: ObjectId, 
        ref: 'Vendor' 
    },
    createdAt: {
      type: Date,
      default: Date.now
    }
});

--这是它变得棘手/具有挑战性的地方:

Vendor/Stores用户可以查找其周围的

,也可以直接搜索Product

如果被要求找到供应商,它会在供应商集合中直接查找--在一定的半径内。

代码语言:javascript
复制
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})

但是,当用户搜索产品时:

系统应该返回搜索产品的详细信息和附近的销售商-从最近到最远,在一定的半径。

为此,我考虑在GeoJSON模式中存储供应商的产品的VendorProduct位置详细信息。

VendorProduct模式与GeoJSON详细信息:

代码语言:javascript
复制
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中存储供应商的位置细节。

几个问题:

  1. 使用MongoDB进行这种用例是正确的吗?
  2. 是正确的设计和方法吗?
  3. ,在MongoDB ?

中,这种地理位置搜索的时间复杂度是多少?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2020-05-18 14:46:17

根据我的理解,您应该只在供应商模式中保存位置坐标,因为它们与供应商相关。旧的VendorProduct模式很好

Case1:用户正在寻找附近的供应商

您需要运行一个查询,以便根据用户的位置查找供应商,并向用户提供供应商列表

为此,你需要跑

代码语言:javascript
复制
Vendor.find({"location.coordinates": {$geoWithin: {$centerSphere: [[User long, User lat], 1/6378.15]}}})

Case2:用户正在寻找他/她可以在附近找到的产品

在这种情况下,还可以先通过上面的查询搜索附近的供应商(记住,如果不需要减少搜索半径,附近的供应商将受到限制)。

一旦您得到了附近的所有供应商,将他们的it保存在一个数组中,让我们调用它

代码语言:javascript
复制
vendorArray = [vendor_id1, vendor_id2.....]

然后在VendorProduct模式中搜索产品

代码语言:javascript
复制
VendorProduct.find({
  vendor : {
    $in: vendorArray
  }
})

以上解决方案只是为了替代在VendorProductSchema中存储位置信息。

现在您需要在从vendorProduct集合中获取产品in之后获取产品详细信息,我建议您应该在vendorProduct中添加产品名称或任何其他要搜索或筛选的字段。

当前方法的缺点在VendorProduct中存储位置坐标的缺点很少

您要在多个集合中保存冗余数据,并且要维护这些数据,而添加/编辑/删除records

  • VendorProduct集合将包含与Vendor集合相比记录的多重no,geojson查询比基本搜索需要更多的计算能力。当数据库扩展时,在VendorProduct

中对几千条记录运行geojson查询比在VendorProduct中运行100条记录更有效。

票数 2
EN

Stack Overflow用户

发布于 2020-05-10 13:25:18

我只知道基本的MongoDB,但我注意到您正在VendorProduct集合中存储位置数据。在这种情况下,如果供应商编辑他们的坐标,那么需要更新多个文档。

相反,您可以将位置保留在供应商集合本身中。在查询时,您可以执行嵌套查询来获取给定名称的产品,其中供应商的坐标值小于x,y。

https://docs.mongodb.com/manual/tutorial/query-embedded-documents/

票数 0
EN

Stack Overflow用户

发布于 2020-05-15 13:18:46

  1. 在这种用例中使用MongoDB是正确的吗?

是的,我看不出为什么不。MongoDB支持geoJSON,并允许以多种方式轻松查询这些信息。

  1. 这是正确的设计和方法吗?

如果我理解你的处境:

用户可以查找其周围的供应商/商店,也可以直接搜索产品。由于基于位置的服务系统应该发送围绕用户的产品,因此考虑将供应商的GeoJSON位置详细信息存储在VendorProduct模式中,以便系统只能够使用供应商的详细信息查询围绕用户的产品。

给定一个特定点(用户位置),在给定半径内查找有可用产品的供应商。

由于产品可以有多个供应商,而且供应商位于位置,因此没有理由重复供应商的位置。如果您确实将供应商位置信息存储在两个地方,比如供应商和产品,那么您的应用程序就不再有一个真理了。试图保持这些文档的同步变得非常混乱。如果您想分离任何内容,我将将供应商的位置分隔到独立索引集合(下面示例中的vendorGEO),并调整当前的供应商文档以指向这个新集合。这样,您可以查询哪些供应商在用户附近,然后抓取供应商,然后只提取所需的供应商,并搜索他们的产品。

下面是一个mongo示例,它根据点的半径(圆)(用户位置)查找所有未排序的位置。

代码语言:javascript
复制
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

你可以用多边形代替。如果你有一个预先定义的区域,比如在城市范围内,多边形会更有用:

一个多边形,它需要四个点,和最初的起点。注意使用嵌套数组设置坐标的方式:

代码语言:javascript
复制
db.collection.find({location: {$geoWithin: {$geometry: {type: "Polygon", coordinates: [[[point 1], [point 2], [point 3], [point 4], [point 1 again]]]}}}})

若要轻松地存储多边形信息,请将它们存储在单独的集合中。

代码语言:javascript
复制
db.areas.insertOne({name: "Example Location", area: {type: "Polygon", coordinates: [[[longA, latA], [longB, latB], [longC, latC], [longD, latD], [longA, latA]]]}})

若要查找某个点是否位于多边形内,请搜索多边形内的一个点,引用定义的区域字段。

代码语言:javascript
复制
db.areas.find({area: {$geoIntersects: {$geometry: {type: "Point", coordinates: [longA, latA]}}}})

  1. 这类地理位置搜索在MongoDB ?

中的时间复杂度是多少?

当使用$geoIntersects或$geoWithin时,您不需要索引,但是增加查询速度是明智的。

对于任何时间复杂性的关注,您都可以通过使用.explain()命令更深入地研究查询规划/优化来了解幕后的情况。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/61683097

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档