查找我的用户所在服务区域内的所有披萨外卖餐厅

问题描述 投票:0回答:1

我正在做一个需要一些地理东西的项目,直到现在我还没有使用过(我对此有点难过,它非常甜蜜)。无论如何,碰壁并寻求专家的建议以了解如何最好地进行。问题来了:

假设我有一份披萨外卖餐厅列表。每个都有一个物理位置 [lng, lat] 和以英里为单位的送货半径。我需要让我的用户能够找到他们所在的所有披萨外卖餐厅。

我们将 mongo/mongoose 与 Node.js 服务器一起使用(如果这有区别的话)。这是查询(不起作用;但可能会更深入地了解我需要做什么)。

属性坐标=用户的[lng, lat],存储如下:

coordinates: {
   type: {type: String, default: 'Point'},
   coordinates: {type: [Number], default: [1, 1]},
}

查询:

try {
    const vendors = await Vendor.find({}, { _id: 0, serviceRadius: 1 });
    const serviceRadiusValues = vendors.map((vendor) => vendor.serviceRadius);
    const aggregatedVendors = await Vendor.aggregate([{
        $geoNear: {
            near: { type: 'Point', coordinates: propertyCoordinates },
                distanceField: 'distance',
                spherical: true,
                maxDistance: { $multiply: [{ $max: serviceRadiusValues }, 1609.34] },
        },
    }]);
    console.log("list: ", aggregatedVendors);
  } catch (error) {
    console.error("Error with stuff here:", error);
  }

我试过这个:

      try {
        const vendors = await Vendor.find();
        const aggregatedVendors = await Vendor.aggregate([{
            $addFields: {
                maxDistance: {
                    $multiply: ['$serviceRadius', 1609.34],
                },
            },
        },
        {
            $match: {
                'physicalLocation.coordinates': {
                    $geoWithin: {
                        $centerSphere: [
                            propertyCoordinates,
                            { $divide: ['$maxDistance', 3959] },
                        ],
                    },
                },
            },
        }]);
  
    } catch (error) {
        console.error("Error with stuff here:", error);
    }

还有

  try {
    const vendorsWithinServiceArea = await Vendor.find({
        'physicalLocation.coordinates': {
            $geoWithin: {
                $centerSphere: [
                    propertyCoordinates,
                    { $divide: ['$serviceRadius', 3959] },
                ],
            },
    }})
    console.log("list: ", vendorsWithinServiceArea)
  } catch (error) {
    console.error("Error with stuff here:", error)
  }

我尝试了一些变体,但问题是我无法在 geoWithin 中使用“动态”字段。而且因为每个餐厅都有自己的deliveryRadius,所以我有点卡住了。我可以通过自己的方式解决这个问题,但我想把它做对。有人推荐了 elasticSearch,所以我将研究使用它来解决这个问题,但并不肯定它可以满足我的需要。有什么建议吗?

node.js database mongodb gis geospatial
1个回答
0
投票

我没有使用 MongoDB 的经验,但这是所有地理空间数据库的常见问题。地理空间过滤器希望使用空间索引来查找相关行。但是如果你必须检查每一行的服务半径,那么使用基于局部性的索引是不可能的。数据库必须假设可能有 1000 英里外的一排服务半径为 2000 英里,因此它必须检查所有内容。

我可以想到解决此查询的两种方法:

  1. 假设某个最大服务半径。您可以检查数据库,找到最大半径,它们可能不会相差太大。说是50英里。然后搜索 50 英里内的所有披萨店。索引的使用并不完美,而且会把地方带到服务半径之外。在
    geoNear
    查询中,您添加了
    distanceField
    ,现在对由
    distance
    计算出的
    geoNear
    小于地点
    serviceRadiusValues
    的地方进行另一个过滤。

如果服务半径相当均匀,这应该表现得很好。

  1. 为每个地方添加服务区多边形。我不知道是否有 MongoDB 语法,但大多数地理空间数据库都有
    ST_Buffer
    或类似的函数,可以围绕给定的几何图形构建多边形。通过用服务区缓冲它们的位置,向每个具有服务区多边形的位置添加一个字段。现在您可以为这个新字段建立索引,并在该服务区域与用户位置相交的位置进行空间过滤。

我会在服务半径变化很大的情况下使用这种方法(在这种情况下不太可能),并且第一种方法必须使用太大的搜索半径。

© www.soinside.com 2019 - 2024. All rights reserved.