Selecting and ordering by distance with GeoAlchemy2. Bad ST_AsBinary wrap - postgresql

I'm trying to select and order stores by their distance to a point with GeoAlchemy2 / PostGIS but for some reason I keep getting an error.
It seems GeoAlchemy2 wraps things with ST_AsBinary, but when I try to select the distance it tries to wrap the result of the distance calculation. I have no idea how to fix this.
I use this ORM query.
distance = (
Store.coordinates.cast(Geometry)
.distance_centroid(query_centroid)
.label('distance')
)
stores = stores.order_by(distance).add_columns(distance)
The model.
class Store(db.Model):
__tablename__ = 'stores'
store_id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String)
address_details = db.Column(db.String)
coordinates = db.Column(Geography('POINT'))
The error I get.
sqlalchemy.exc.ProgrammingError: (psycopg2.ProgrammingError) function st_asbinary(double precision) does not exist
LINE 1: ...Binary(stores.coordinates) AS stores_coordinates, ST_AsBinar...
^
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
[SQL: 'SELECT stores.store_id AS stores_store_id,
stores.name AS stores_name,
stores.address_details AS stores_address_details,
ST_AsBinary(stores.coordinates) AS stores_coordinates,
ST_AsBinary(CAST(stores.coordinates AS geometry(GEOMETRY,-1)) <-> ST_GeomFromEWKT(%(param_1)s)) AS distance
FROM stores ORDER BY distance']13 -46.730347)'}]
[parameters: {'param_1': 'POINT(-23.3569
The problem is precisely in this part...
ST_AsBinary(
CAST(stores.coordinates AS geometry(GEOMETRY,-1))
<->
ST_GeomFromEWKT(%(param_1)s)
) AS distance
Notice how ST_AsBinary wraps the distance between the two points instead of wrapping just the geom, for example? (I'm not sure it should wrap the geom in this case, either)
Can anyone help? I just want to know how far things are.

An average user at freenode answered it for me.
GeoAlchemy2 will convert columns of type Geometry if they are in the select statement. Even though the result of the distance expression is a double, and not a Geometry, GeoAlchemy2 isn't smart enough to figure that out.
The column needs to be explicit cast in the ORM.
The fixed query:
distance = (
Store.coordinates.cast(Geometry)
.distance_centroid(query_centroid)
.cast(db.Float)
.label('distance')
)
stores = stores.order_by(distance).add_columns(distance)

Related

Cassandra Select Query for List and Frozen

I have user define type like
CREATE TYPE point ( pointId int, floor text);
And I have table like:
CREATE TABLE path (
id timeuuid,
val timeuuid,
PointList list<frozen <point>>,
PRIMARY KEY(id,val)
);
And have create index like
create index on path(PointList);
But the problem is I am not able to execute select query where PointList = [floor : "abc"].
I google for 2 hours but not able to find the hint.
I am using this query to execute select query
Select * from path where val = sdsdsdsdsds-dsdsdsd-dssds-sdsdsd and PointList contains {floor: 'eemiG8NbzdRCQ'};
I can see this data in my cassandra table but not able to get that data using above query.
I want select query where we can only use floor and val. Because we only have data for floor and val
I tried many different ways but nothing is working.
I would appreciate any kind of hint or help.
Thank you,
Frozen point means point type is frozen, you can't partially provide point value, you have to provide the full value of point
Example Query :
select * from path where pointlist CONTAINS {pointId : 1, floor : 'abc'};

How to make a GIS query on PostgreSQL without use ST_X("Position4326") function

I have written this geographical query:
SELECT
ST_X("Position4326") AS lon,
ST_Y("Position4326") AS lat,
"Values"[4] AS ppe,
"Values"[5] AS speed
FROM
(
SELECT
*
FROM
"SingleData"
UNION ALL
SELECT
*
FROM
"SingleDataOld"
) AS d
WHERE
"Values"[5] > 0
and its work.
But I would like to select a specific area in the database, e.g.:
Lat_min = 43.77;
Lat_max = 43.88;
Lon_min = 12.95;
Lon_max = 13.05;
to reduce the time of working.
It is possible do this without use ST_X and ST_Y function? Or, better: I would like use a WHERE clause, but the format of geographical data are Position4326, an alphanumeric string that I do not know how manipulate.
The format of position4326 could be of geometry type or geography type. Postgis offer a big range of functions which you can use to limit the result data improve the performance.
I.e. use can the function ST_MakeEnvelope and the && operator:
WHERE ...
AND Position4326 && ST_MakeEnvelope(xmin, ymin, xmax, ymax, srid);
in latitude/longitude terms, the arguments are so:
ST_MakeEnvelope(long_min, lat_min, long_max, lat_max, srid);
Because you column is named Position4326, I guess you should use srid = 4326.
ST_MakeEnvelope(12.95, 43.77, 13.05, 43.88, 4326);
Also ensure that you have a spatial index on the column Position4326:
CREATE INDEX Position4326_gix ON your_table USING GIST (Position4326);

operator does not exist: geography <-> geography

I've postgresql column with type
geography(Point,4326)
And I've inserted some rows to it using
POINT(LONG LAT)
That data have been inserted successfully and I can retrieve it with no problems, now I want to get the nearest entries to a specific point using the following query
SELECT "cafes".* FROM "cafes" ORDER BY "latlng" <-> (SELECT latlng FROM cafes WHERE id = '3') LIMIT 1
But I'm getting the following error
ERROR: operator does not exist: geography <-> geography
LINE 1: ...es".* FROM "cafes" ORDER BY "latlng" <-> (SELEC...
^
HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.
The <-> "distance between" operator applies to PostgreSQL geometric data types, not to the PostGIS geography data type. With the geography data type you can use the PostGIS function ST_Distance() and find the minimum value.
WITH this_cafe (latlng) AS (
SELECT latlng FROM cafes WHERE id = '3'
)
SELECT cafes.*, ST_Distance(cafes.latlng, this_cafe.latlng, 'false') AS dist
FROM cafes, this_cafe
ORDER BY dist ASC
LIMIT 1
Note that the third argument useSpheroid to the function is set to false which will make the function much faster. It is unlikely going to affect the result because cafes tend to lie close to each other.
This assumes that there is only 1 cafe with id = 3. If there could be more, then restrict the CTE to return just 1 row.

How to convert self-defined types, e.g. geometry, to and from String?

There is geometry type column in database like Postgis or h2gis(I am using it).
In the console provided by database, I can create a geometry value with select ST_GeomFromText('POINT(12.3 12)', 4326).
Or select a column with geometry type simply by select * from geom.
However I don't know how to insert a geometry value (a string actually) into a table or the opposite direction conversion.
There are also several miscellaneous question below.
Here is the table definition in slick:
class TableSimple(tag:Tag) extends Table[ (Double,String,String) ](tag,"tb_simple"){
def col_double = column[Double]("col_double",O.NotNull)
def col_str = column[String]("col_str",O.NotNull)
def geom = column[String]("geom",O.DBType("Geometry"))
def * = (col_double,col_str,geom)
}
1. About select
The most simple one:
sql" select col_double,col_str, geom from tb_simple ".as[(Double,String,String)]
won't work unless casting geom to string explicitly like:
sql" select col_double,col_str, cast( geom as varchar) from tb_simple ".as[(Double,String,String)]
The first sql throws the error java.lang.ClassNotFoundException: com.vividsolutions.jts.io.ParseException
Q1: How does slick know com.vividsolutions.jts.io.ParseException (it is lib used by h2gis)? Is it an error on the server side or client side(slick side)?
Q2: How to convert/treat column geom as string without writing too much code(e.g. create a new column type in slick)?
2. About insert
First of all the following sql works
StaticQuery.updateNA(""" insert into tb_simple values(11,'abcd',ST_GeomFromText('POINT(5.300000 1.100000)', 4326)) """).execute
I hope code like TableQuery[TableSimple] += (10.3,"hello","ST_GeomFromText('POINT(0.300000 1.100000)'") would work but it doesn't.
It shouldn't because slick translate it to
insert into tb_simple values(11,'abcd','ST_GeomFromText(''POINT(5.300000 1.100000)'', 4326)')
Notice the function ST_GeomFromText become a part of string, that's why it doesn't work.
Q3: Can I implant a string directly for a column instead of wrapped with '' in slick?
I hope I can insert a row as easy as TableQuery[TableSimple] += (10.3,"hello","ST_GeomFromText('POINT(0.300000 1.100000)'") or similar code.
Q4 What's the most convenient way in Slick to implement bidirectional conversion to and from String for a geometry or other self-defined column in the database?
Answering you main question: Slick-pg offers mapping of geometry types in the db to actual geometry types in your model.
It works for Postgis, but maybe it can also work with H2Gis.
You can find slick-pg at https://github.com/tminglei/slick-pg

How to create geoalchemy expression for a point geometry?

I have a table with lat and long, i don't want to store geometry.
Instead i am storing lat and longs.
How to create point based queries using position expression? basically it should return point.
Which should be converted to SQL expression like ".....ST_Point(home.latitude, home.longitude)....."
There is no func.ST_Point in geoalchemy ? or am i missing something ?
if i dont write expression obviously i get
"sqlalchemy.exc.InternalError: (InternalError) parse error - invalid geometry
HINT: "POINT(Ve" <-- parse error at position 8 within geometry"
Code:
class Home(Base):
__tablename__ = 'vehicle_path'
id = Column(BigInteger, primary_key=True)
latitude = Column(Float)
longitude = Column(Float)
#hybrid_property
def position(self):
return WKTElement(
''.join(['POINT(', str(self.longitude),' ', str(self.latitude), ')']), 4326)
#position.expression
def position(cls):
return <???what to return???>
I am using sqlalchemy, Geoalchmey2 with postgis, postgres, pyramid.
It sounds like you are looking for WKTElement http://geoalchemy-2.readthedocs.org/en/latest/elements.html#geoalchemy2.elements.WKTElement There is an ST_MakePoint(x,y) function in Postgis, but not in Geoalchemy it would seem. As a matter of interest, why would you want to store latitude and longitude instead of a geometry (or Point in your case). You can easily recover the latitude and longitude from the geometry using ST_X(geom), ST_Y(geom), but more importantly you can put a spatial index on a geometry column, which will perform much better than two separate non-spatial columns for any kind of spatial queries.