1

Exposition

Let's say our system has users and some games. Let's call these games A, B and C.

For simplicity's sake, our initial tables look like this:

CREATE TABLE IF NOT EXISTS users (
    id SERIAL PRIMARY KEY
);

CREATE TABLE IF NOT EXISTS games (
    id SERIAL PRIMARY KEY
);

Problem

Whenever we play these games and finish them, we have to record statistics related to the game for the specific user. For example, for game A we have to record total_jumps and total_crouches because the game's mechanics allow such accumulation, however games B and C might require us to record other total_* fields (though, the prefix total_ is not necessary). How do I store this information?

I'm troubled with the solution for this problem. I have come up with 2 approaches:

Solution 1

Have a single table for this:

CREATE TABLE IF NOT EXISTS statistics (
    user_id SERIAL REFERENCES users (id) ON DELETE CASCADE,
    game_id SERIAL REFERENCES games (id) ON DELETE CASCADE,
    fields JSONB,
    PRIMARY KEY (user_id, game_id)
);

This way we leave it to the application level to parse arbitrary data coming from the fields column.

Solution 2

Have multiple tables, one for each game:

CREATE TABLE IF NOT EXISTS A_statistics (
    user_id SERIAL PRIMARY KEY REFERENCES users (id) ON DELETE CASCADE,
    total_jumps INTEGER,
    total_crouches INTEGER
);

Personally, solution #2 looks better to me, but... this problem still bothers me a lot. As if I am missing something, because neither of the options make extension (adding new games) any easier? Say we add games D, E and F. Both solutions require us in some way to handle specific fields (at the application level) required for these games. Is that something I just have to come to terms with? Or is there a third, better solution to this that I just don't see?

New contributor
ncmprbl is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
3
  • 1
    Hi, and welcome to dba.se! How many games/sports will you be looking at? I don't see any problem with having a table for each sport/game - they all have different rules so your backend (and frontend) will have have to treat them differently anyway! The data entry screens will be different... &c.
    – Vérace
    Commented Dec 5 at 19:15
  • @Vérace, ah, it's not too many games - we're just talking about hypothetical numbers in case there was an actual extension. But thank you for your reply on the topic!
    – ncmprbl
    Commented Dec 5 at 22:17
  • With respect to the JSON - PostgreSQL has a JSONB type (plus a plain JSON - more or less deprecated now) that you could use to "pick-n-mix" your model - its performance compares favourably to MongoDB - see here and here - although, the authors say you should perform your own benchmarks - but at least they have been "honest and transparent" - 50 pages of a .pdf and loads of github stuff - data/results! À vous le choix!
    – Vérace
    Commented Dec 6 at 9:26

2 Answers 2

1

You could use a non-relational database to store this kind of data. For example, in mongoDB you could have a games collection. Then in your application code, you might have multiple data models:

FootballGame total_passes

BoxingGame total_punches

Each of these data models would save to the same collection, which is made possible due to the use of a non-relational database.

Further, each of these data models could inherit from a base Game model with some common properties.

Each data model will store some kind of discriminator which denotes the game. This would be needed so that your application code knows how to load a saved game from the database, i.e. what data model the document saved corresponds to. See https://mongoosejs.com/docs/discriminators.html#discriminators

New contributor
Shahram is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
3
  • The disadvantage to Solution 2 (having multiple tables) is that if you wanted to count the number of games a player has played, you would have to enumerate across all the game tables. The number of tables will increase as you add more games. The same for any common property between the game tables that you'd like to query on.
    – Shahram
    Commented Dec 5 at 20:53
  • Migration to a non-relational database is not feasible at the moment (although, I'll take a look at the link you sent here), but I see your point since that was also one of my concerns. I had my reservations about solving this problem with a relational database but oh well.
    – ncmprbl
    Commented Dec 5 at 22:21
  • You can have both. It's very common to have both as many systems store a combination of relational and non-relational data.
    – Shahram
    Commented Dec 5 at 22:26
0

Relational database management systems expect well-defined data structures - the "relations" in the name. So having runtime-variable needs is a known hard problem.

That said, most recent versions of everything handle JSON well. Having some JSON parsing in a SQL query need not hurt performance much.

Starting with a single JSON column will get you up & running. Over time you will find that many queries read the same metric, or certain games are overwhelmingly popular. Add a column for these specifically and write the value to the column and also to JSON. In other words, start with 1 and move to 2 over time.

If you research long enough you will read about the "entity attribute value" model. It will work well enough at small scale (depending on hardware) but, in my experience, gets real ugly real quick once you're no longer small.

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.