API 完整指南:GeoJSON 数据类型与地理位置查询操作符)
Laf 云数据库地理信息GEOAPI 完整指南GeoJSON 数据类型与地理位置查询操作符【免费下载链接】lafLaf is a vibrant cloud development platform that provides essential tools like cloud functions, databases, and storage solutions. It enables developers to quickly unleash their creativity and bring innovative ideas to life with ease.项目地址: https://gitcode.com/GitHub_Trending/la/lafLaf 云数据库database-ql内置了完整的地理位置支持允许在文档中存储经纬度点、路径、多边形等 GeoJSON 几何对象并通过geoNear、geoWithin、geoIntersects三个查询操作符实现附近的人、区域圈选、路径相交等 LBS 场景。本文以 Laf 官方文档《地理信息 API》为骨架结合packages/database-ql的源码实现带你掌握 6 种 GEO 数据类型的构造与校验规则、3 个 GEO 操作符的精确语义与参数约束并给出可直接落地的查询示例。使用前提必须建立地理位置索引⚠️如果需要对类型为地理位置的字段进行搜索一定要建立地理位置索引否则查询无法命中或触发数据库层面的索引缺失错误。地理查询尤其是geoNear依赖索引来完成距离排序与空间剪枝。请提前在云数据库控制台或通过管理 API为存储地理位置字段例如location创建地理位置索引2dsphere然后再执行本文中的任何 GEO 查询示例。GEO 数据类型GEO 类型通过db.Geo命名空间暴露packages/database-ql/src/index.ts中将其声明为interface GeoType { Point: typeof Geo.Point LineString: typeof Geo.LineString Polygon: typeof Geo.Polygon MultiPoint: typeof Geo.MultiPoint MultiLineString: typeof Geo.MultiLineString MultiPolygon: typeof Geo.MultiPolygon } readonly Geo: GeoType Geo即在db.Geo下可直接取用Point、LineString、Polygon、MultiPoint、MultiLineString、MultiPolygon六个类见 geo/index.ts。所有 GEO 对象在写入数据库时都会序列化为标准的GeoJSON 结构typecoordinates从而与 MongoDB 的空间索引天然兼容。Point用于表示地理位置点用经纬度唯一标记一个点这是一个特殊的数据存储类型。签名Point(longitude: number, latitude: number)示例new db.Geo.Point(longitude, latitude);在源码 point.ts 中构造时会通过Validate.isGeopoint校验经纬度其合法范围分别为latitude纬度[-90, 90]longitude(经度)[-180, 180]序列化后的 GeoJSON 结构为{ type: Point, coordinates: [longitude, latitude] }注意 coordinates 数组中先经度后纬度与构造参数顺序一致。LineString用于表示地理路径是由两个或者更多的Point组成的线段。签名LineString(points: Point[])示例new db.Geo.LineString([ new db.Geo.Point(lngA, latA), new db.Geo.Point(lngB, latB), // ... ]);源码 lineString.ts 对构造参数做了严格校验points必须是数组至少包含 2 个Point否则抛出points must contain 2 points at least数组中的每个元素都必须是Point实例否则抛出TypeError。此外LineString.isClosed(line)会判断首尾点经纬度是否完全相等该工具方法被Polygon复用以校验闭环。Polygon用于表示地理上的一个多边形有洞或无洞均可它是由一个或多个闭环LineString组成的几何图形。由一个环组成的Polygon是没有洞的多边形由多个环组成的是有洞的多边形。对由多个环LineString组成的多边形Polygon第一个环是外环所有其他环是内环洞。签名Polygon(lines: LineString[])示例new db.Geo.Polygon([ new db.Geo.LineString(...), new db.Geo.LineString(...), // ... ])源码 polygon.ts 中的构造约束lines必须是数组且至少包含 1 个LineString每个元素必须是LineString实例每个环都必须是闭环即该LineString的首点与尾点经纬度完全一致否则抛出LineString ... is not a closed cycle。因此闭合区域的正确写法是首尾坐标相同例如new db.Geo.Polygon([ new db.Geo.LineString([ new db.Geo.Point(lngA, latA), new db.Geo.Point(lngB, latB), new db.Geo.Point(lngC, latC), new db.Geo.Point(lngA, latA), // 回到起点形成闭环 ]), ]);序列化后为 GeoJSON 的Polygoncoordinates是一个环数组的数组每个环由[lng, lat]坐标对组成。MultiPoint用于表示多个点Point的集合。签名MultiPoint(points: Point[])示例new db.Geo.MultiPoint([ new db.Geo.Point(lngA, latA), new db.Geo.Point(lngB, latB), // ... ]);源码 multiPoint.ts 要求points为数组、至少包含 1 个Point且所有元素必须是Point实例。MultiLineString用于表示多个地理路径LineString的集合。签名MultiLineString(lines: LineString[])示例new db.Geo.MultiLineString([ new db.Geo.LineString(...), new db.Geo.LineString(...), // ... ])源码 multiLineString.ts 要求lines为数组且至少包含 1 个LineString每个元素必须是LineString实例注意MultiLineString内部路径不要求闭环闭环约束只在Polygon中强制。MultiPolygon用于表示多个地理多边形Polygon的集合。签名MultiPolygon(polygons: Polygon[])示例new db.Geo.MultiPolygon([ new db.Geo.Polygon(...), new db.Geo.Polygon(...), // ... ])源码 multiPolygon.ts 要求polygons为数组且至少包含 1 个Polygon每个元素必须是Polygon实例。由于每个Polygon在构造时已校验过闭环MultiPolygon保证了整体结构的合法性。序列化结构速查与 geo/interface.ts 中定义一致Point为[number, number]LineString/MultiPoint为[number, number][]Polygon/MultiLineString为[number, number][][]MultiPolygon为[number, number][][][]。嵌套层级随几何维度递增。GEO 操作符GEO 操作符统一通过db.command暴露。在 command.ts 中geoNear、geoWithin、geoIntersects分别构造对应的QueryCommand枚举见 commands/query.ts 中的GEO_NEAR、GEO_WITHIN、GEO_INTERSECTS并可与where、and、or等普通查询条件自由组合。geoNear按从近到远的顺序找出字段值在给定点的附近的记录。返回结果自带距离排序近 - 远。签名db.command.geoNear(options: IOptions) interface IOptions { geometry: Point // 点的地理位置 maxDistance?: number // 选填最大距离米为单位 minDistance?: number // 选填最小距离米为单位 }示例db.collection(user).where({ location: db.command.geoNear({ geometry: new db.Geo.Point(lngA, latA), maxDistance: 1000, minDistance: 0, }), });源码层面的约束commands/query.tsgeometry必须是Point实例否则抛出TypeErrormaxDistance、minDistance若传入则必须是数字单位均为米语义上minDistance 记录与给定点的球面距离 maxDistance按距离升序返回。该查询典型应用于查找我附近 1 公里内的用户/门店也可配合limit实现附近的 Top N。补充geoNear同样可用于聚合管道。在 aggregate.ts 中聚合阶段通过_pipe(geoNear, param)透传geoNear参数适合在聚合场景中同时计算距离字段或做后续分组统计。geoWithin找出字段值在指定 Polygon / MultiPolygon 内的记录无排序。适合做地理围栏 / 区域圈选。签名db.command.geoWithin(IOptions); interface IOptions { geometry: Polygon | MultiPolygon; // 地理位置 }示例// 一个闭合的区域 const area new Polygon([ new LineString([ new Point(lngA, latA), new Point(lngB, latB), new Point(lngC, latC), new Point(lngA, latA), ]), ]); // 搜索 location 字段在这个区域中的 user db.collection(user).where({ location: db.command.geoWithin({ geometry: area, }), });源码约束geometry只能是Polygon或MultiPolygon实例见 commands/query.ts传入Point、LineString等其他类型会抛出TypeError。结合上文这里的Polygon必须是闭环结构若要圈选多个互不相连的区域请使用MultiPolygon。geoIntersects找出字段值和给定的地理位置图形相交的记录。支持任意几何类型作为相交目标适合做路径与区域、点与区域之间的叠加分析。签名db.command.geoIntersects(IOptions); interface IOptions { geometry: | Point | LineString | MultiPoint | MultiLineString | Polygon | MultiPolygon; // 地理位置 }示例// 一条路径 const line new LineString([new Point(lngA, latA), new Point(lngB, latB)]); // 搜索 location 与这条路径相交的 user db.collection(user).where({ location: db.command.geoIntersects({ geometry: line, }), });源码约束geometry必须是六种 GEO 类型中的任意一种Point、LineString、Polygon、MultiPoint、MultiLineString、MultiPolygon否则抛出TypeError。它不像geoNear那样要求目标为点、也不像geoWithin那样要求目标为面是最通用的空间关系查询例如找出所有骑行路线与某条河流相交的打卡记录。三个操作符选型小结操作符目标 geometry 类型是否排序典型场景geoNearPoint按距离由近到远附近的人、周边门店、Top N 最近点geoWithinPolygon/MultiPolygon否地理围栏、区域圈选、电子地图行政区块geoIntersects全部六种类型否路径/区域/点之间的相交分析三者均可与db.command的其他逻辑操作符如and、or组合共同构建更复杂的空间 属性混合查询。实战综合示例假设user集合中每个文档包含location字段Point类型以下是一个同时按城市围栏过滤 按距离排序的混合查询const cityArea new db.Geo.Polygon([ new db.Geo.LineString([ new db.Geo.Point(116.0, 39.5), // 北京某区域外环 new db.Geo.Point(116.6, 39.5), new db.Geo.Point(116.6, 40.2), new db.Geo.Point(116.0, 40.2), new db.Geo.Point(116.0, 39.5), // 闭合 ]), ]); db.collection(user) .where({ location: db.command.geoWithin({ geometry: cityArea }), age: db.command.gte(18), // 叠加普通条件 }) .limit(50) .get();关于db实例的初始化方式可参考 database-ql 快速开始 与 database-ql 文档目录。注意事项先建索引对地理位置字段执行geoNear、geoWithin、geoIntersects前务必先建立地理位置索引2dsphere否则查询无法正确执行。坐标顺序Point构造参数与 GeoJSONcoordinates均为[经度, 纬度]注意与直觉上的纬度在前区分。闭环约束Polygon的每个环首尾坐标必须完全一致由多个环构成时第一个环为外环其余为内环洞内环同样必须是闭环。单位geoNear的maxDistance/minDistance单位为米。类型约束geoNear只接受PointgeoWithin只接受Polygon/MultiPolygon传入其他类型会在构造命令时立即抛出TypeError见 commands/query.ts提前使用正确的几何类型可以避免运行时错误。上述所有类型与操作符的完整实现可在仓库packages/database-ql/src/geo/与packages/database-ql/src/commands/query.ts中进一步阅读接口序列化定义参见 geo/interface.ts。【免费下载链接】lafLaf is a vibrant cloud development platform that provides essential tools like cloud functions, databases, and storage solutions. It enables developers to quickly unleash their creativity and bring innovative ideas to life with ease.项目地址: https://gitcode.com/GitHub_Trending/la/laf创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考