1.postgresql9.4 版本
2.请先安装postgis和postgis_topology 插件
3.jsonb操作自定义函数,9.4以前不支持jsonb单值更新
4.9.5+以解决加入了|| 和jsonb_set 等操作符和函数
#创建数据库
CREATE DATABASE samtest
WITH
OWNER = postgres
ENCODING = 'UTF8'
CONNECTION LIMIT = -1;
#添加启用postgis
-- Extension: postgis
-- DROP EXTENSION postgis;
CREATE EXTENSION postgis;
-- Extension: postgis_topology
-- DROP EXTENSION postgis_topology;
CREATE EXTENSION postgis_topology;
#创建表
-- Table: public.poi_test
-- DROP TABLE public.poi_test;
CREATE TABLE public.poi_test
(
id bigserial NOT NULL, --自增加id
name character varying(50), --动串
location geometry, --地理信息点格式
extinfo jsonb, --其它信息
createtime timestamp without time zone, --时间戳
PRIMARY KEY (id)
)
WITH (
OIDS = FALSE
);
ALTER TABLE public.poi_test
OWNER to postgres;
#创建geo索引
CREATE INDEX poi_test_location_index
ON public.poi_test
USING gist
(location);
#创建jsonb索引
CREATE INDEX public_poi_test_index_extinfo ON public.poi_test USING GIN (extinfo);
#插入表
INSERT INTO public.poi_test ( name, location,extinfo,createtime ) VALUES ( '马泉营B口',GeomFromEWKT('SRID=4326;POINT(116.510431 40.040612)'),'{"type":"地铁"}',current_timestamp);
INSERT INTO public.poi_test ( name, location,extinfo,createtime ) VALUES ( '汉堡啤酒餐厅',GeomFromEWKT('SRID=4326;POINT(116.511791 40.040477)'), '{"type":"饭店","ali_type":"餐厅"}',current_timestamp);
INSERT INTO public.poi_test ( name, location,extinfo,createtime ) VALUES ( '马泉营C口停车场',GeomFromEWKT('SRID=4326;POINT(116.510691 40.039383)'), '{"type":"地铁"}',current_timestamp);
INSERT INTO public.poi_test ( name, location,extinfo,createtime ) VALUES ( '丽苑小区',GeomFromEWKT('SRID=4326;POINT(116.516844 40.041461)'), '{"type":"小区"}',current_timestamp);
#9.4版以下,需要自定义jsonb更新函数
--start------------------------------------------------------------------------------------
/*
* derivative work of Matheus de Oliveira's json_manipulator.sql
* https://gist.github.com/matheusoliveira/9488951
*
* adapted to support postgresql 9.4 jsonb type
* no warranties or guarantees of any kind are implied or offered
*
* license is as Matheus conferred it on 4/9/2015:
* matheusoliveira commented on Apr 9
* @hannes-landeholm, I'd like to take credit if you share them
* (a link to this gist is more than enough), but I don't care
* much about licensing, consider it public domain, modify and
* use as you will.
* https://gist.github.com/matheusoliveira/9488951
*/
--jsonb插入追加
CREATE OR REPLACE FUNCTION public.jsonb_append(data jsonb, insert_data jsonb)
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
SELECT json_object_agg(key, value)::jsonb
FROM (
SELECT * FROM jsonb_each(data)
UNION ALL
SELECT * FROM jsonb_each(insert_data)
) t;
$$;
--删除
CREATE OR REPLACE FUNCTION public.jsonb_delete(data jsonb, keys text[])
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
SELECT json_object_agg(key, value)::jsonb
FROM (
SELECT * FROM jsonb_each(data)
WHERE key <> ALL(keys)
) t;
$$;
--合并
CREATE OR REPLACE FUNCTION public.jsonb_merge(data jsonb, merge_data jsonb)
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
SELECT json_object_agg(key, value)::jsonb
FROM (
WITH to_merge AS (
SELECT * FROM jsonb_each(merge_data)
)
SELECT *
FROM jsonb_each(data)
WHERE key NOT IN (SELECT key FROM to_merge)
UNION ALL
SELECT * FROM to_merge
) t;
$$;
--更新
CREATE OR REPLACE FUNCTION public.jsonb_update(data jsonb, update_data jsonb)
RETURNS jsonb
IMMUTABLE
LANGUAGE sql
AS $$
SELECT json_object_agg(key, value)::jsonb
FROM (
WITH old_data AS (
SELECT * FROM jsonb_each(data)
), to_update AS (
SELECT * FROM jsonb_each(update_data)
WHERE key IN (SELECT key FROM old_data)
)
SELECT * FROM old_data
WHERE key NOT IN (SELECT key FROM to_update)
UNION ALL
SELECT * FROM to_update
) t;
$$;
CREATE OR REPLACE FUNCTION public.jsonb_lint(from_json jsonb, ntab integer DEFAULT 0)
RETURNS jsonb
LANGUAGE sql
IMMUTABLE STRICT
AS $$
SELECT (CASE substring(from_json::text FROM '(?m)^[\s]*(.)') /* Get first non-whitespace */
WHEN '[' THEN
(E'[\n'
|| (SELECT string_agg(repeat(E'\t', ntab + 1) || jsonb_lint(value, ntab + 1)::text, E',\n') FROM jsonb_array_elements(from_json)) ||
E'\n' || repeat(E'\t', ntab) || ']')
WHEN '{' THEN
(E'{\n'
|| (SELECT string_agg(repeat(E'\t', ntab + 1) || to_json(key)::text || ': ' || jsonb_lint(value, ntab + 1)::text, E',\n') FROM jsonb_each(from_json)) ||
E'\n' || repeat(E'\t', ntab) || '}')
ELSE
from_json::text
END)::jsonb
$$;
CREATE OR REPLACE FUNCTION public.jsonb_unlint(from_json jsonb)
RETURNS jsonb
LANGUAGE sql
IMMUTABLE STRICT
AS $$
SELECT (CASE substring(from_json::text FROM '(?m)^[\s]*(.)') /* Get first non-whitespace */
WHEN '[' THEN
('['
|| (SELECT string_agg(jsonb_unlint(value)::text, ',') FROM jsonb_array_elements(from_json)) ||
']')
WHEN '{' THEN
('{'
|| (SELECT string_agg(to_json(key)::text || ':' || jsonb_unlint(value)::text, ',') FROM jsonb_each(from_json)) ||
'}')
ELSE
from_json::text
END)::jsonb
$$;
--end------------------------------------------------------------------------------------------------------------------------------------
#全量替换更新
update public.poi_test set location=GeomFromEWKT('SRID=4326;POINT(116.510691 40.039383)') where name='马泉营C口停车场';
update public.poi_test set extinfo='{"type":"饭店","ali_type":"餐厅"}'::jsonb where name='汉堡啤酒餐厅';
#字符串替换更新
select replace(extinfo::text,'"type": "饭店"','"type":"饭店111"')::jsonb from public.poi_test ;
update public.poi_test set extinfo=replace(extinfo::text,'"type": "饭店"','"type":"字符串替换更新"')::jsonb where name='汉堡啤酒餐厅';
#使用自定义函数更新jsonb_update
select jsonb_update('{"type":"饭店","ali_type":"餐厅"}'::jsonb,'{"type":"1111"}'::jsonb);
update public.poi_test set extinfo=jsonb_update(extinfo::jsonb,'{"type":"自定义函数更新1"}'::jsonb) where name='汉堡啤酒餐厅';
update public.poi_test set extinfo='[{"type":"饭店","ali_type":"餐厅"}]'::jsonb where name='汉堡啤酒餐厅';
#jsonb_update
select jsonb_append('{"type":"饭店2","ali_type":"餐厅2"}'::jsonb,'{"aaa":"aaaa"}'::jsonb);
#jsonb_delete
select jsonb_delete('{"type":"饭店2","ali_type":"餐厅2"}'::jsonb,array['type']);
#jsonb_merge
select jsonb_merge('{"type":"饭店2","ali_type":"餐厅2"}'::jsonb,'{"aaaa":"合并的"}'::jsonb);
#查询
select *,ST_AsText(location),extinfo::jsonb from public.poi_test where name like '马泉%';
select *,ST_AsText(location) from public.poi_test where name = '丽苑小区';
select *,ST_AsText(location) from public.poi_test where extinfo @>'{"type":"地铁"}';
select *,ST_AsText(location),extinfo->'type' as type from public.poi_test where extinfo @>'{"type":"地铁"}';
#查询500M内的地点,按近远排序
select * ,ST_Distance(GeomFromEWKT('SRID=4326;POINT(116.510431 40.040612)'), location) km from public.poi_test where ST_Distance(GeomFromEWKT('SRID=4326;POINT(116.510431 40.040612)'), location)<0.005 order by km asc;
select * ,ST_Distance(GeomFromEWKT('SRID=4326;POINT(116.510431 40.040612)'), location) km from public.poi_test where ST_Distance(GeomFromEWKT('SRID=4326;POINT(116.510431 40.040612)'), location)*1000<5 order by km asc;