存储 GeoJson 点并在给定距离/半径内查找点 | NODEJS、Postgres、NestJs、TypeOrm

Posted

技术标签:

【中文标题】存储 GeoJson 点并在给定距离/半径内查找点 | NODEJS、Postgres、NestJs、TypeOrm【英文标题】:Storing GeoJson points and finding points within a given distance/radius | NODEJS, Postgres, NestJs, TypeOrm 【发布时间】:2021-07-29 19:17:03 【问题描述】:

提前谢谢你。 我已经在互联网上搜索了一个工作示例/文档,用于存储位置点(经度、纬度)、查找两点之间的距离、查找给定距离内的点。 我正在使用 typeorm、nestjs、postgresql。

(我已经尝试过 Mariadb,但 St_distance_sphere 在那里不起作用,所以我会使用 postgresql)

这是我的实体

@ApiProperty(
    type: String,
    title: 'current_location',
    example: '"type":"Point","coordinates":[28.612849, 77.229883]',
  )
  @Index( spatial: true )
  @Column(
    type: 'geometry',
    srid: 4326,
    nullable: true,
    spatialFeatureType: 'Point',
    transformer: 
      to: (v: Point) => 
        console.log(JSON.stringify(v));
        return eval(`ST_GeomFromGeoJSON($JSON.stringify(v))`);
      ,
      from: (v: any) => 
        return  type: 'Point', coordinates: [v.x, v.y]  as Point;
      ,
    ,
  )
  current_location: string;

似乎有太多的 postgres/postgis 文档,但对我的情况没有任何用处。 任何帮助深表感谢。我已经坚持了一个多星期。

*注意:我不想使用 JSONB 数据类型,因为它的速度较慢。

【问题讨论】:

【参考方案1】:

以下代码将存储在数据库中并查找范围内的位置

技术栈nestJS,typeorm,postgres,postgis extension,@types/geojson

testlocation.entity.ts

import  Column, Entity, Index, PrimaryGeneratedColumn from 'typeorm';
import  Geometry, Point  from 'geojson';

@Entity( name: 't_test_location' )
export class TestLocation 
  @PrimaryGeneratedColumn('increment')
  pk_id: number;
  
  @Column( type: 'varchar', name: 's_city' )
  city: string;

  @Column( type: 'double precision', name: 'd_lat' )
  lat: number;

  @Column( type: 'double precision', name: 'd_long' )
  long: number;

  @Index( spatial: true )
  @Column(
    type: 'geography',
    spatialFeatureType: 'Point', 
    srid: 4326,
    nullable: true,
  )
  location:Point

location.service.ts

import  Injectable  from '@nestjs/common';
import  InjectRepository  from '@nestjs/typeorm';
import  TestLocation  from 'src/model/testlocation.entity';
import  getManager, QueryBuilder, Repository  from 'typeorm';
import  Geometry, Point  from 'geojson';
@Injectable()
export class LocationService 
  constructor(
    @InjectRepository(TestLocation) private readonly repo: Repository<TestLocation>,
  ) 

  public async getAll() 
    return await this.repo.find();
  
  
  public async create(location:TestLocation)
    const pointObject :Point= 
      type: "Point",
      coordinates: [location.long,location.lat]
  ;
  location.location = pointObject;
  return await this.repo.save(location)
  

  public async getRange(lat:number,long:number,range:number = 1000) 
    let origin = 
      type: "Point",
      coordinates: [long, lat]
    ;
   let  locations = await this.repo
        .createQueryBuilder('t_test_location')
        .select(['t_test_location.city AS city','ST_Distance(location, ST_SetSRID(ST_GeomFromGeoJSON(:origin), ST_SRID(location)))/1000 AS distance' ])
        .where("ST_DWithin(location, ST_SetSRID(ST_GeomFromGeoJSON(:origin), ST_SRID(location)) ,:range)")
        .orderBy("distance","ASC")
        .setParameters(
           // stringify GeoJSON
          origin: JSON.stringify(origin),
          range:range*1000 //KM conversion
        )
       .getRawMany();
    return locations;
  


location.controller.ts

import  Body, Controller, Get, Post  from '@nestjs/common';
import  TestLocation  from 'src/model/testlocation.entity';
import  LocationService  from './location.service';

@Controller('location')
export class LocationController 
  constructor(private serv: LocationService) 

  @Get()
  public async getAll() 
    return await this.serv.getAll();
  
  @Post()
  createLocation(@Body() location : TestLocation): void
    this.serv.create(location);
  
  @Post('range')
 public async getRange(@Body() location : 
    lat:number,
    long:number,
    range:number
  )
    return await this.serv.getRange(location.lat,location.long,location.range);
  



【讨论】:

非常感谢@Pradeep 我在 6 天前就知道了:这是我的笔记:hussainwali.medium.com/… 收到此错误:QueryFailedError: type "geography" does not exist 可能是什么原因? TestLocation 中为什么有 lat、long 和一个 Point,这个 Point 就足够了吗? 是的,点就够了。出于调试目的,我保留了它。

以上是关于存储 GeoJson 点并在给定距离/半径内查找点 | NODEJS、Postgres、NestJs、TypeOrm的主要内容,如果未能解决你的问题,请参考以下文章

在Shapely中查找路径起点的坐标距离

从给定位置(经度、纬度)的 Y 半径内查找 X 的所有值

Caliburn.Micro 点击事件查找图像点并计算距离

使用经度和纬度查找给定距离内的所有附近客户

确定给定半径算法内的点

Geojson笔记二:geojson-python-util