【问题标题】:Storing GeoJson points and finding points within a given distance/radius | NODEJS, Postgres, NestJs, TypeOrm存储 GeoJson 点并在给定距离/半径内查找点 | 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 数据类型,因为它的速度较慢。

【问题讨论】:

    标签: node.js postgresql nestjs geojson typeorm


    【解决方案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 就足够了吗?
    • 是的,点就够了。出于调试目的,我保留了它。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-07-21
    • 1970-01-01
    • 1970-01-01
    • 2018-11-25
    • 1970-01-01
    相关资源
    最近更新 更多