Sequlize How to store array of strings in SQLite table column - sql

I need to store array of strings in column and make queries by this column. I tried to use JSON data type of column but i need to make [Op.like] query by this json column. Example:
{
actors: {
[Op.like]: `%${actor}%`,
},
},
But it does not work.

You can store an array of actors in the movies table, but this is not an efficient way to store lists in SQL.
Instead, use a many-to-many relationship. This means having a separate actors table, and a table to link actors to movies.
const Movies = sequelize.define(
MOVIES,
# Add columns as normal, but no actors column.
);
const Actors = sequelize.define(
ACTORS,
# Add columns as normal.
);
Movies.belongsToMany(Actors);
Actors.belongsToMany(Movies);
And then query a movie actors with include.
const movie = await Movies.findOne({
where: { title: "Bad Taste" },
include: Actors,
});
# and now work with movie.actors
This is faster, and more flexible. Actors can appear in many movies without having to duplicate their data, and you can store as much data as you want for an actor. SQL will enforce that every actor for every movie actually exists.

Related

Should I extract the "time" part of "timestamp" into "json" data type?

I am designing a database(postgresql) that can store a user's meals across the day, and there'll be weekly, monthly, or yearly analysis based these everyday information in the future. My original design was to have a meals table that looks like:
meals (table name)
id (primary key)
user_id (foreign key)
picture_ids
labels
note
timestamp
With this structure, querying data of a user's meals in a specified day may first filter meals by user_id, then by timestamp. And for one user, there will be multiple records inserted for multiple meals during one day.
Another way is use [json or jsonb type](https://www.postgresql.org/docs/current/datatype-json.html) to extract the "time" part from `timestamp` so the `timestamp` only contains 'year', 'month', 'date', thus I may have a table named `meals_of_day`:
meals_of_day (table name)
id (primary key)
user_id (foreign key)
records (json type) <----------
date
And data in the records column may look like:
{
"08:30": {
picture_ids: [1,2],
labels: ['meat', 'apple'],
note: 'meat was too salty'
},
"12:45": {
// some data
},
"19:05": {
// some data
}
}
This way, one user only has one row for each day, insertion of a meal is actually an updating of the records column of the row corresponding to user+date.
Which approach will have a shorter response time when a user log in a meal?
If the analytical feature involves a lot of time related queries, which approach would be more efficient?
Thanks.
Of the two approaches (and knowing nothing about your application layer, front-end architecture, etc) I'd prefer the meals table approach. It's simple, fairly flexible (seems to make few assumptions about how the data will be used), prevents possible update-conflicts on the jSONB structure, and is fairly simple to migrate away from (to the mails_per_day approach or something else) should the need arise.

Displaying Multiple Rows of Data from Two Tables with a One to Many Relationship

I have two tables. Tracks and metadata. Tracks can have multiple metadata attributes, but metadata can only be attached to a single track. The metadata table has a foreign key for a track ID, but the tracks table has no foreign keys for metadata. I am trying to find the best way to get this result:
[{
trackID: 6,
trackName: "test", /* these are the data from the tracks table */
metadata: [
{
bpm: 123 /* This is the data from the metadata table */
},
...
]
},
{
trackID: 7,
trackName: "test2",
metadata: [
{
bpm: 135
},
...
]
}]
Essentially, i am trying to get multiple tracks, with each track having multiple metadata attributes. The only way i've been able to think of doing this is to first query for the tracks
SELECT * FROM tracks;
then on the backend, for each track returned send another query
SELECT * FROM metadata WHERE track=?
What is the better way of doing this, without sending many many queries to the database?
I have also tried a JOIN such as:
SELECT * FROM tracks LEFT JOIN metadata ON metadata.track = track.id WHERE track.id>5 LIMIT 10 ;
but this would require parsing it on the backend and checking each row to see if it has an identical track ID and overall also seems sluggish and suboptimal.
Is there a better way of doing this, what is the best practice here? Thank you in advance.
PS: I am using Postgres, NodeJS and Prisma if that helps.
You should use aggregation. It is not clear exactly what your data looks like and what you want the results to look like. For instance, if you only want the bpm column from metadata (as your results suggests), then this puts that value in an array column called metadata:
SELECT t.track_id, t.name,
ARRAY_AGG(m.bpm) as metadata
FROM tracks t LEFT JOIN
metadata m
ON m.track = t.id
WHERE t.id > 5
GROUP BY t.track_id, t.name;
If you want additional columns, you can put the entire record in the array:
ARRAY_AGG(m) as metadata
And Postgres supports all of this with JSON functions as well.

Database design - Category-Object relation

I have to store in database objects with different kind of properties. Also I want to group those objects in categories and the object can be part in multiple categories.
Example objects:
Book (ID, Title, Author, Description)
Movie (ID, Title, Author, Genre)
Song (ID, Title, Singer, Year)
So far I have tried two methods:
Method 1
Create a Category table with fields ( ID, CategoryName).
Create a general table and try to match table fields with object properties.
Join the category with objects in a helper table
_CategoyObject_ (_CategoryID_, _ObjectID_).
This seems to be a bad practice because we have many columns with null values in general table. Also referring to the first point in this article it is a bad practice to store different objects in the same table.
Method 2
Create a Category table with fields ( ID, CategoryName).
Create table for each of the object.
Create a helper table to link the categories table with the name of the object table:
_CategoyObject_ (_CategoryID_, *Object_Table_Name*)
This method can help us find the name of the table to create the join if we want to take objects for a given category.
But this complicates the query because we should have one query to get the tables for a certain category and another query to get records of objects
This is even harder because I am currently using Entity Framework code first to create the database.
Is it better to get the data with ADO.NET instead of Entity Framework for easier data retrieval?
Can you suggest me any other method that is simpler for the questions:
Get all the objects who belongs to X category?
Get in which category Y object belongs?
Create three tables, and call them movies, books, and songs. In this way, you will not need to look up the name of the table. When you need the books, you'll "select * from books".

SQL Database layout/design

I'm creating a music player that is backed by a SQLite database. There's a songs table that has an id, title, artist, album, etc. I'm currently trying to make playlists and I'd like to know whether my design will be efficient. Initially I wanted to make a table of playlists and each playlist entry would have a list of song ids. I would then query the songs table for the list of song ids. Something along the lines of SELECT * FROM songs where id=this OR id=that OR id=..... However, I've just read up on joins so now I'm thinking that each playlist should be its own table and entries for a playlist table would just be ids from the songs table and I can do an inner join on the song id column between a specific playlist table and the songs table. Which method would be more efficient? Are they equivalent?
When you find yourself considering creating multiple identical tables holding similar data you probably should take a step back and rethink your design as this is contrary to the idea underlying the relational model. The same goes for the idea of storing "lists of ids", which I interpret to mean some kind of array of data, something that also is a bad fit for a good model as every item in a row (or tuple) should only store one value.
One possible design for your domain could be this:
Songs (SongID PK, SongAttributes (name, length etc) ...)
Playlists (PlaylistID PK, PlaylistAttributes (like name, owner etc) ...)
PlaylistSongs (PlaylistID FK, SongID FK)
PK = Primary Key, FK = Foreign Key
To select all songs songs for a certain playlist:
select songs.name
from songs
join playlistsongs on songs.songid = playlistsongs.songid
join playlist on playlist.playlistid = playlistsongs.playlistid
where playlist.name = '???'
As for your questions: Which method would be more efficient? Are they equivalent?
Neither would be good, and they're not equivalent. In the first example you would probably get problems with retrieving and updating data, and in the other the number of tables would be linear to the number of playlists, and you would have to inject every query you make with the suitable table name at run-time - this is really something that you do not want.
OR statements become inefficient very quickly, so a model with playlist and a playlist id, is an option.
Example:
SONG ----> PLAYLIST WITH LIST OF SONGIDs
Pseudo code:
CREATE TABLE SONG (
song_id INT,
name VARCHAR,
other attributes);
CREATE TABLE playlists (
playlist_id INT,
song_id INT REFERENCES FOREIGN KEY song(song_id),
other playlist attributes);
Then you can join the list:
SELECT a.*, b.*
FROM playlists a
INNER JOIN song b ON a.song_id=b.song_id AND a.playlist_id=?;
which will give you the playlist of a certain person owning playlist_id X.

How to display multiple values in a MySQL database?

I was wondering how can you display multiple values in a database for example, lets say you have a user who will fill out a form that asks them to type in what types of foods they like for example cookies, candy, apples, bread and so on.
How can I store it in the MySQL database under the same field called food?
How will the field food structure look like?
You may want to read the excellent Wikipedia article on database normalization.
You don't want to store multiple values in a single field. You want to do something like this:
form_responses
id
[whatever other fields your form has]
foods_liked
form_response_id
food_name
Where form_responses is the table containing things that are singular (like a person's name or address, or something where there aren't multiple values). foods_liked.form_response_id is a reference to the form_responses table, so the foods liked by the person who has response number six will have a value of six for the form_response_id field in foods_liked. You'll have one row in that table for each food liked by the person.
Edit: Others have suggested a three-table structure, which is certainly better if you are limiting your users to selecting foods from a predefined list. The three-table structure may be better in the case that you are allowing them the ability to enter their own foods, though if you go that route you'll want to be careful to normalize your input (trim whitespace, fix capitalization, etc.) so you don't end up with duplicate entries in that table.
normally, we do NOT work out like this. try to use a relation table.
Table 1: tbl_food
ID primary key, auto increment
FNAME varchar
Table 2: tbl_user
ID primary key, auto increment
USER varchar
Table 3: tbl_userfood
RID auto increment
USERID int
FOODID int
Use similar format to store your data, instead a chunk of data fitted into a field.
Querying in these tables are easier than parsing the chunk of data too.
Use normalization.
More specifically, create a table called users. Create another called foods. Then link the two tables together with a many-to-many table called users_to_foods referencing each others foreign keys.
One way to do it would be to serialize the food data in your programming language, and then store it in the food field. This would then allow you to query the database, get the serialized food data, and convert it back into a native data structure (probably an array in this case) in your programming language.
The problem with this approach is that you will be storing a lot of the same data over and over, e.g. if a lot of people like cookies, the string "cookies" will be stored over and over. Another problem is searching for everyone who likes one particular food. To do that, you would have to select the food data for each record, unserialize it, and see if the selected food is contained within. This is a very inefficient.
Instead you'll want to create 3 tables: a users table, a foods table, and a join table. The users and foods tables will contain one record for each user and food respectively. The join table will have two fields: user_id and food_id. For every food a user chooses as a favorite, it adds a record to the join table of the user's ID and the food ID.
As an example, to pull all the users who like a particular food with id FOOD_ID, your query would be:
SELECT users.id, users.name
FROM users, join_table
WHERE join_table.food_id = FOOD_ID
AND join_table.user_id = users.id;