Commit 2dc98ed3 authored by Shane A. Stillwell's avatar Shane A. Stillwell 🎯

Add button to edit post

parent bd4b30d5
---
title: "The Wonderful and Dangerous to_json from Postgres"
date: 2018-10-31T08:39:02-05:00
draft: true
tags:
- postgresql
---
[PostgreSQL](https://www.postgresql.org/) is an amazing [RDBMS](https://en.wikipedia.org/wiki/Relational_database_management_system). Not only is has it been [ACID compliant since 2001](https://www.postgresql.org/about/), it supports many data types and functions, putting it on par with Document Store systems like MongoDB. Postgres supports a wide range of JSON formats and methods to store, search, and transform JSON object data. For instance, the `to_json` and related function `json_agg` allow you to collect a row into a JSON object. Handy for when you have nested data and want PG to return an object with nested values.
## An Example Usage of to_json
Let's take a look at how to use `to_json` in your queries. A really simple example involving two tables. The following SQL should create and populate two tables.
```sql
CREATE TABLE company (
id SERIAL PRIMARY KEY,
name text,
website text
);
CREATE UNIQUE INDEX company_pkey ON company(id int4_ops);
CREATE TABLE person (
id SERIAL PRIMARY KEY,
name text,
phone text,
company_id integer REFERENCES company(id)
);
CREATE UNIQUE INDEX person_pkey ON person(id int4_ops);
INSERT INTO "public"."company"("id","name","website")
VALUES
(1,E'Apple',E'www.apple.com'),
(2,E'Google',E'www.google.com');
INSERT INTO "public"."person"("id","name","phone","company_id")
VALUES
(1,E'Shane',E'3035551212',1),
(2,E'Larry',E'4045551212',2);
```
Now we can get the rows in `person` with nested JSON values for the `company`
```sql
select person.*, to_json(company) as company
from person
left join company on company.id = person.company_id;
```
This gives us a nice JSON array of results
```JSON
[
{
"id" : 1,
"phone" : "3035551212",
"company" : {"id":1, "name":"Apple", "website":"www.apple.com"},
"name" : "Shane",
"company_id" : 1
},
{
"id" : 2,
"phone" : "4045551212",
"company" : {"id":2, "name":"Google", "website":"www.google.com"},
"name" : "Larry",
"company_id" : 2
}
]
```
Do you see how we get a nice JSON array with nested values for the `person.company`? This makes app development a breeze. We no longer have to make two different queries and stitch tegther the results, PG performs the hard work for us.
**NOTE**: You can use `json_agg`, which will give you a JSON array for one-to-many relationships. We're not going to cover it here, but in all likelihood, you'll need to utilize `group by` when using `json_agg`
## What's so Dangerous?
Glad you asked. By converting the rows you return to JSON, you lose the specific types of the fields. Now the `company` field is JSON and the items within just use primitive JSON types (string, numbers, boolean, arrays, objects). Now you lose any type of specific postgres driver sugar.
### An Example in a current app
I'm working on a app utilizing the PG [Range Types](https://www.postgresql.org/docs/9.3/static/rangetypes.html). In this instances, it's the `int4range` type to signify age ranges. For example, it might have age range values of `[0, 10)`, or `[10, 15)`, or `[15, 100)`. This is **range type** literal notation for *Number range begining at 0 and ending on 9*. I also use a really handy Node.js postgres tool [pg-range](https://www.npmjs.com/package/pg-range), it will detect a range field and automagically parse the field into other properties, such as `begin`, `end`, and some nice comparison methods.
The problem, when I use `to_json`, the fields returned for `age_range` is not a `int4range`, but rather a `text` data type. Therefor, it doesn't get converted by the *pg-range* driver and I lose the ability to call `.begin` or `.end` on that field.
......@@ -41,6 +41,7 @@
</div>
{{ partial "post_tags.html" . }}
{{ partial "edit_page.html" . }}
</article>
{{ partial "authorbox.html" . }}
{{ partial "post_nav.html" . }}
......
<div class="post__tags tags clearfix">
<ul class="tags__list">
<li class="tags__item">
<a href="https://gitlab.com/shanestillwell/www.shanestillwell.com/blob/master/content/{{ .File.Path }}" class="tags__link"><strong>Improve this page</strong></a>
</li>
</ul>
</div>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment