6

In our current application we are basically going to provide something called "translations" for each field. So a table would originally be like:

CREATE TABLE organisation (
   id SERIAL PRIMARY KEY,
   name TEXT NOT NULL DEFAULT '',
)

But instead the name would now be language dependent.

The basic solution would be to no longer store the name field in the organisation table but instead in an "organisation_language" table:

CREATE TABLE organisation (
   id SERIAL PRIMARY,
);  


CREATE TABLE organisation_language
(
  id SERIAL PRIMARY KEY,
  organisation INTEGER NOT NULL,
  field_name TEXT NOT NULL,
  field_language TEXT NOT NULL,
  field_translation TEXT NOT NULL DEFAULT '',
  
  FOREIGN KEY (organisation)
    REFERENCES public.organisation (id) MATCH SIMPLE
      ON UPDATE CASCADE
      ON DELETE CASCADE
      NOT VALID
);

(And yes I'm deliberately ignoring I could add a lookup table for language keys like en-US and refer to that).

However, now I can no longer "guarantee" that every field (like name) is defined. Of course the code could make sure it does but that's another layer. It also adds quite a bit of complexity as it is no longer easy to see what fields even belong to a datamodel. Or what translations are given for a certain organisation.

If I look at the JSON I would actually "like" my backend to send to the frontend upon requesting "data from organisation 1" it would look like:

{
    id: 1
    name: {
        "en-us": 'hello world',
        "nl-nl": 'hoi wereld'
    }
}

On top of that, the main actions that happen are "insertion" - but then insertion of all data at once (so all translations at once), and retrieval of all language data, not ever a single language. (Due to "paths", like if a field doesn't exist in en-gb check en-us, and this calculation happens in backend).

Modification happens so rarely that we are even considering to just "not support it" and instead go for copy-on-write and deactivating the old "organisation".


This made me think, is it a bad idea to change the type of the "name" field to JSON, instead of having a language table? (and do this for all fields). It would then look like:

CREATE TABLE organisation 
(
  id SERIAL PRIMARY KEY,
  name JSON NOT NULL DEFAULT '{}'::JSON
);

And inserted data into the name field would be (backend has to verify the schema):

{
    "en-us": 'hello world',
    "nl-nl": 'hoi wereld'
}

Is there an actual drawback to using JSON fields, as opposed to using a language table? It has the advantage of easier lookup, and insertion (or deletion). And since modification is not supposed to happen anyways there's no drawback - correct?

Or will PostgreSQL choke on this later?

1
  • hstore is another option. It's a simple string->string map, which seems like a close fit for your data model. Commented May 3, 2021 at 19:05

2 Answers 2

5

The first normal form requires columns to be single, atomic values. I'd argue that if you really treat these JSON objects as something to store and retrieve, they are atomic from a database point of view, and what you plan to do is fine.

If you want to use parts of the JSON in a WHERE condition, that could still be alright. If you want database constraints based on parts of the JSON, or you want to join based on JSON attribute, I'd advise against using such a data model.

2
  • Some constraints like CHECK name->'default' IS NOT NULL might actually be easier to expression on a JSON attribute than in a properly normalised database schema. (Admittedly, they'd require AND jsonb_typeof(name->'default') = 'string')
    – Bergi
    Commented May 3, 2021 at 21:37
  • 1
    @Bergi I think you could easily have that constraint in a normalized data model. But of course I am generalizing. Judging from the questions I see, way too many people use JSON in the database when they shouldn't. Commented May 4, 2021 at 1:23
4

As a_horse_with_no_name originally mentioned in comments:

With the restrictions you describe - no searching or modification through SQL - the JSON column seems a good fit.

As an aside, you should consider the jsonb data type instead of json. They differ only in the internal representation. To the application using them there is no difference (apart from the re-ordering of the keys - but the order of the keys shouldn't matter to a properly coded application anyway). When you retrieve the values from the database you can't distinguish a value coming from a jsonb column from one coming from a json column.

The manual recommends jsonb over json:

In general, most applications should prefer to store JSON data as jsonb, unless there are quite specialized needs, such as legacy assumptions about ordering of object keys.


On the other hand, json might still be better than jsonb, because it avoids the overhead of parsing the data into the internal binary representation. json is essentially a string with a check for a valid JSON value.

0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.