Sequelize select statement for this example with express get method - mysql

I have these 2 words:
The words in mysql db
And I have this category:
The category
As we can see in the word-table, the words have also a categoryId attribute.
I've made an junctiontable in case I need it but it's currently empty, it looks like that:
junction table
I want to display a list in my ui that is a admin-panel that would look like this for example:
Words
Category
God
Religion
Ford Mustang
Cars
Every word has exactly one category.
To do that I want to use axios to fetch a get request of my node.js server.
What would look the get method with the corresponding sequelize query to get the data and maybe also the method in the react ui?
I'm trying to figure it out for about two days now and I can't get out of this shithole...
What is the project*:**
Full stack web app that simulates the game "wheel of fortune". Contains a auth-system where admins can also make CRUD options for words, questions and create categories that belong to a word or question. Classic users can only play the game.
Technologies:
React -> Frontend
Node.js Backend -> Express.js and Sequelize
Database: MySQL with mysql workbench

Assuming model name for Words table is Word and Category for category table the code to query all the data would be such:
const words = await Word.findAll({
where: {
// here you can do filtering if needed
},
include: [
{
model: Category,
attributes: [
'category',
],
as: 'categories',
},
],
});
This will return list of words and associated categories. Then you would just create api endpoint and return queried data and display on frontend.

Related

multi-tenancy Join or multiple Select queries postgres

I am implementing multi tenancy using single database and separating data for each tenant using a tenant_id. This id is passed in the jwt token as well. I have two tables right now genre and books. genre table has columns like
tenant_id, genre_id, ..... and books table has columns genre_id, book_id, book_name, ....
So 1 genre can have multiple books associated with it and 1 tenant can have multiple genres associated with it.
Now every time a book is fetched or updated I want to make sure the right person is making these calls.
I know of two ways to do it.
First way:
Make two queries. First fetch the book, get the associated genre_id in the object. Then fetch that genre and compare the jwt tenant_id with the tenant_id inside this genre object.
Something like this
const book= await ReadBook(req.query.book_id); // fetches my book from db
const genre = await ReadBook(book.genre_id); // fetches the genre from db
if (genre.tenant_id === jwtToken.tenant_id) {..} // compare if same or not
Second way:
Do this query in db
select b.*, g.tenant_id as tenant_id
from book_data b, genre_data g
where b.book_id = '0eokdpz0l' and g.tenant_id = 'M1MzgzMDM' and b.genre_id = g.genre_id
Which method is more efficient?
If theres a more efficient method then these then please let me know too
It's good practice to stick to ORM abstraction if possible, while minimising how much and how often data is transferred to/from db. Sequelize is able to construct an equivalent to that query for you, with the necessary joins and filters on the ids. Something among the lines of:
Books.findAll({
where: {book_id: '0eokdpz0l'},
include: [{
model: Genre,
where: {tenant_id : jwtToken.tenant_id}
}]
}).then(books => {
/* ... */
});
Running multiple queries in sequence not only adds latency due to additional round trips to/from db (and possibly connection setup if you're not pooling or holding them open) but it's also moving more bytes of data around, needlessly. tenant_id mismatch on db would send back a shorter message with an empty result. Checking it on client side requires downloading data even when you'll have to discard it.

How to count total amount of comments per posts in nodejs, react js and sequelize?

I am working on a project where a user can ask and answer a question so in the comments filed I have trouble with it.
the comments table is working well and displaying the data and can delete the data, but I want to count the total number of comments per post.
These blooks of codes are working well but it counts all the comments in the table, that's what I don't want, I want to display the total number of each post not all the amount of the comments in one post.
router.get("/commentsCounter/:id", async (req, res) => {
const id = req.params.id;
const commentsCounter = await Comments.count(id);
res.json({commentsCounter});
console.log('commentsCounter', commentsCounter)
});
in the comment table, I have commentbody,author name, and postId.
Do any suggestions, please?
Sequelize count method takes an object as its argument which you can specify your post ID in its where attribute. So in your case you want to change your query to
const commentsCounter = await Comments.count({ where: { postId: id} });
Without seeing the full code (DB call, what the select statement looks like etc) it's hard to say..
But, typically if you DB is setup to have say 'posts' and 'comments' tables and the comment table has something like id AND parentID (the ID of the parent POST in the 'posts' table) you should be able to do it fairly easily using javascript OR the DB query itself
If you are doing it on the DB side, you would typically add a COUNT to the select statement OR once you have the results of the query you can just do a 'length' of the returned object to get the total returned.
*** Edit ***
As #Pouya had pointed out, you can doing via the SQL query as show in his post, this will count the number of responses based on the select, this does require a query per though, again without knowing the full flow of this this may or may not be what you are looking for but would give you the count based on the specific query.
Now, if you are say, returning a large object of ALL replies and want to get just the responses for a specific subset you will want to look at filtering your return object by the right key/value
something like
let myArr = [{id:'123',name:'item1'},{id:'234',name:"item2"},
{id:'123',name:"item3"}]
//filter just id 123
// filter syntax is [array].filter(variable => [key you want to filter on].includes("[value to filter on]")
let newArray = myArr.filter(p => p.id.includes('123'));
//our new array
console.log(newArray)
Should get you just a subset of the array, then you can just do
let replyCount = newArray.length

How would you model a collection of users and friends in Firebase?

I'm trying to create a database (json) with Firebase.
I searched the docs and the net but couldn't find a clear way to start.
I want to have a database of users.
each user (represented as UID) should have a nickname and a list of friends.
I tried making a .json file that looks like this:
{
users:{
}
}
and adding it to the Firebase console to get started but it wouldn't work.
How can I do it?
the database should look like this:
{
users:{
UID:{
nickname: hello
friends: UID2
}
UID2:{
nickname: world
friends: UID
}
}
I don't know if I got that right, so I would really appreciate any help you guys could give me at this subject.
Thanks in advance!
Seems like a good place to start. I would make two changes though.
keep the list is friends separate
keep the friends as a set, instead of a single value or array
keep the list is friends separate
A basic recommendation when using the Firebase Database is to keep your data structure shallow/flat. There are many reasons for this, and you have at least two.
With your current data structure, say that you want to show a list of user names. You can only get that list by listening to /users. And that means you don't just get the user name for each user, but also their list of friends. Chances that you're going to show all that data to the user are minimal, so that means that you've just wasted some of their bandwidth.
Say that you want to allow everyone to read the list of user names. But you only want each user to be able to read their own list of friends. Your current data structure makes that hard, since permission cascades and rules are not filters.
A better structure is to keep the list of user profiles (currently just their name) separate from the list of friends for each user.
keep the friends as a set
You current have just a single value for the friends property. As you start building the app you will need to store multiple friends. The most common is to then store an array or list of UIDS:
[ UID1, UID2, UID3 ]
Or
{
"-K.......1": "UID1"
"-K.......5": "UID2"
"-K.......9": "UID3"
}
These are unfortunately the wrong type for this data structure. Both the array and the second collection are lists: an ordered collection of (potentially) non-unique values. But a collection of friends doesn't have to be ordered, it has to be unique. I'm either in the collection or I'm not in there, I can't be in there multiple times and the order typically doesn't matter. That's why you often end up looking for friends.contains("UID1") or ref.orderByValue().equalTo("UID1") operations with the above models.
A much better model is to store the data as a set. A set is a collection of unordered values, which have to be unique. Perfect for a collection of friends. To store that in Firebase, we use the UID as the key of the collection. And since we can't store a key without a value, we use true as the dummy value.
So this leads to this data model:
{
users:{
UID:{
nickname: hello
}
UID2:{
nickname: world
}
}
friends:{
UID:{
UID2: true
}
UID2:{
UID: true
}
}
}
There is a lot more to say/learn about NoSQL data modeling in general and Firebase specifically. To learn about that, I recommend reading NoSQL data modeling and watching Firebase for SQL developers.
I keep a collection of Friends where the users field is an array of 2 user ids: ['user1', 'user2'].
Getting the friends of a user is easy:
friendsCollection.where("users", "array-contains", "user1").get()
This should get you all documents where user1 appears.
Now the tricky part was on how to query a single friend. Ideally, firebase would support multiple values in array-contains, but they won't do that: https://github.com/firebase/firebase-js-sdk/issues/1169
So they way I get around this is to normalize the users list before adding the document. Basically I'm utilizing JS' truthiness to check what userId is greater, and which is smaller, and then making a list in that order.
when adding a friend:
const user1 = sentBy > sentTo ? sentBy : sentTo
const user2 = sentBy > sentTo ? sentTo : sentBy
const friends = { users: [user1, user2] }
await friendsCollection.add(friends)
This basically ensures that whoever is part of the friendship will always be listed in the same order, so when querying, you can just:
await friendsCollection.where("users", "==", [user1, user2]).get()
This obviously only works because I trust the list will always have 2 items, and trust that the JS truthiness will work deterministically, but it's a great solution for this specific problem.

RESTful API complex queries

I have a simple restful api for destinations. It's built using Express and sequelize with a MySQL database.
It has Cities, Countries and Regions. Cities belongTo Countries which belongsTo Regions.
Now, it's usual that I have to do complex find operations. For example:
GET /cities
{
where: {
name: {'$like': 'bue%'}
},
include: [{model: Country, where: {region_id: 1}}]
}
With this I am trying to fetch all cities where the name starts with 'bue', but only whose country's region_id is 1.
This could be taken one step forward if I specify which fields I want returned. The models have some text fields which I might not need, so the above query becomes:
{
where: {
name: {'$like': 'bue%'}
},
attributes: ['id', 'name'],
include: [{
model: Country,
attributes: ['id', 'name'],
where: {region_id: 1}
}]
}
This is already quite complex. Image if I want to include the Country's region and add some filter there as well.
So, my question is: how do I go about passing this complex query?
Right now I am using url params with encoded json. So I have something like:
where: {name: {'$like': 'bue%'}} => Becomes:
/cities?where=%7Bname%3A%20%7B%27%24like%27%3A%20%27bue%25%27%7D%7D
You can see that this results in a damn ugly URL that is quite hard to work with. If my query is complex, the URL becomes a monster. If my where param as OR / AND and complex conditions, it gets really big and messy.
Anyway, that's the question. Should I keep things as they are. Is there any more proper way to do this somehow.
Some example would be appreciated.
One sort of "standard" solution is to POST the complex query (with the query in the HTTP body), let the server store it somewhere and return a new URL that references the stored query. After that clients can issue a GET on the new query URL to get the result.

MongoDB query for related records

I have a blog application. I need to make a MongoDB query (SQL is fine, I'll translate it), to get a specific post in the blog, and the immediate posts made before and after that post.
For instance, given this list of posts:
12/01/13 - Foo
15/01/13 - Bar
17/01/13 - Baz
27/01/13 - Taz
How do I write a query so that I get one of these, i.g Bar, and the immediate siblings Foo and Baz?
I'd like to do this without making three different queries to the database, for performance reasons.
In my application I fetch a single post like this:
model.findOne({
date: {
$gte: new Date(2013, 0, 15),
$lt: new Date(2013, 0, 15, 24)
},
slug: 'Bar'
}, function(result){
return { entry: result };
});
Here's one possibility (involving 2 queries, one to find the primary post, and the second to find the nearest doc):
Treat the data/posts as if it were a doubly-linked list.
You'll need to store reference IDs as links to the "previous" and "next" posts in each post document (array). This makes inserts a tiny more complex, but inserting a "new" blog post by date somewhere in the past seems unlikely.
Index the link field
Search for documents having the id of the primary document $in the link field