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.
Related
I'm pretty new in App Maker. I want to create an app that will collect various types of request (failures, new ideas, orders and so on ). For each type of request will be separate data model. Every data model (request) contains 3 the same information: date, applicient, comments.
In addition to the dashboard's stand for each type of request, I want to make one in which all entries will be displayed with only repating records and type of request as one more record (date, applicient, comments, type of request)
I think that Calculated Model is the answer here, but despite getting acquainted with the documentation, I don't know how to implement this in my case. Could anybody halp me with this ?
Below I am presenting the display of the above description. Records 1, 2, 3 ... presents records that don't replicate in another data model.
IMAGE:
https://drive.google.com/file/d/1gi6ylZacOVSkcqtpaupRpIOrzbq7fOsT/view?usp=sharing
I tried to do relations, but I couldn't displey this in one table, what is my goal. How to conigure the SQL datasource to do this ?
You can create a new calculated SQL model with UNION:
(SELECT 'Failures' AS REQUEST_TYPE, C.* FROM Failures AS C)
UNION ALL
(SELECT 'New Ideas', C.* FROM `New ideas` AS C)
UNION ALL
(SELECT 'Orders', C.* FROM Orders AS C);
You must have corresponding fields in your datasource that match the sql column names: REQUEST_TYPE, Date, Applicient, Comments
Reference:
Cloud sql model
I would like some help as the data structure in Firebase. I've read the API guide and some blog articles like these:
Queries, Part 1: Common SQL Queries Converted for Firebase
Firebase: Now with more querying!
Denormalizing Your Data is Normal
I'm leaving SQL (MySQL and SQLite specifically) and trying to migrate to Firebas. I would like to know how to structure these tables and relationships for a structured JSON in Firebase.
Relationship 1-1; 1 - N; N - N;
I'm sending a picture of an example database containing some relationships, could you give me this support would look like this in the database you? Remembering that I need to consult with the data about the same as would query in SQL.
This is my Database:
I'll take a shot at this...
First and foremost, Firebase is not a relational database so it should not be thought of in those terms. However, you can craft 'relationships' between data that (for an end user) feels 'relational'
Let's use a Departments and Employees-like example. A department can have many employees and those employees belong to that department.
departments
dept_00
dept_name: "Bridge"
dept_01
dept_name: "Engineering"
dept_02
dept_name: "Medical"
crew
crew_00
crew_name: "Kirk"
in_dept: "dept_00"
crew_01
crew_name: "Scotty"
in_dept: "dept_01"
crew_02
crew_name: "Bones"
in_dept: "dept_02"
crew_04
crew_name: "Spock"
in_dept: "dept_00"
With this structure, a query can be performed for crew that are bridge members: here's an ObjC snippit
Firebase *ref = [myRootRef childByAppendingPath:#"crew"];
FQuery *q1 = [ref queryOrderedByChild:#"in_dept"];
FQuery *q2 = [q1 queryEqualToValue:#"dept_00"];
[q2 observeEventType:FEventTypeChildAdded withBlock:^(FDataSnapshot *snapshot) {
NSLog(#"%#", snapshot.value);
}];
This will return the crew_00 (Kirk) and the crew_04 (Spock) nodes.
Note the disassociation between the data (Bridge, Engineering) and the node name (dept_00, dept 01). This allows the data to be modified without breaking 'links' between them. So I could rename 'Engineering' to 'Scotty's Hideaway' and everything will continue to work. Those 'random' node names would be generated by a push() in firebase or ChildByAutoId (objc)
Likewise, if we know the crew member name (Bones) we could query for that specific node to return that he belongs to dept_02 (Medical).
You could expand beyond this in cases where say, Spock and Bones belongs to several different departments, say Bridge and Engineering, by adding another node to track which departments the crew member belongs to:
belongs_to
crew_02
dept_00: true
dept_02: true
crew_04
dept_00: true
dept_01: true
Here, crew_02 (Bones) is now in the Medical and Bridge departments (much to Spocks dismay) and crew_04 (Spock) is now in the Bridge and Engineering Department. With this added belong_to node, the in_dept child nodes could be removed from the crew node.
That should cover one to one, one to many and many to many
I have a design problem with SQL request:
I need to return data looking like:
listChannels:
-idChannel
name
listItems:
-data
-data
-idChannel
name
listItems:
-data
-data
The solution I have now is to send a first request:
*"SELECT * FROM Channel WHERE idUser = ..."*
and then in the loop fetching the result, I send for each raw another request to feel the nested list:
"SELECT data FROM Item WHERE idChannel = ..."
It's going to kill the app and obviously not the way to go.
I know how to use the join keyword, but it's not exactly what I want as it would return a row for each data of each listChannels with all the information of the channels.
How to solve this common problem in a clean and efficient way ?
The "SQL" way of doing this produces of table with columns idchannel, channelname, and the columns for item.
select c.idchannel, c.channelname, i.data
from channel c join
item i
on c.idchannel = i.idchannel
order by c.idchannel, i.item;
Remember that a SQL query returns a result set in the form of a table. That means that all the rows have the same columns. If you want a list of columns, then you can do an aggregation and put the items in a list:
select c.idchannel, c.channelname, group_concat(i.data) as items
from channel c join
item i
on c.idchannel = i.idchannel
group by c.idchannel, c.channelname;
The above uses MySQL syntax, but most databases support similar functionality.
SQL is made for accessing two-dimensional data tables. (There are more possibilities, but they are very complex and maybe not standardized)
So the best way to solve your problem is to use multiple requests. Please also consider using transactions, if possible.
I have a database setup as follows (unfortunatelly was not allowed to publish diagram image in here so need to describe:
Responses table - contain RespondentID, QuestionID, ResponseOptionID
ResponseProperties - contain ResponsePropertyID, ResponsePropertyTypeID, Name
ResponsePropertyTypes - contain ResponsePropertyTypeID, Name
ResponsesInProperties (a many to many table) - contains ResponseID, ResponsePropertyID
There is a many to many relationship on ResponsesInProperties table. This table does not show in EF of course.
Say I have two response property types "Country" and "Wave" and corresponding ResponeProperties "USA", "UK" and "Wave2011", "Wave2012".
Now I need to get back from the database all (and not duplicated) responses that would be in USA and also in Wave2012. The trick is that every response I need must be in both Wave2012 and USA. I am trying to achieve this with LINQ to SQL. The below is Linq I came up with that get's me the correct records but they appear many times for different properties. Limiting the properties gives me no records whatsoever....
Any help appreciated!
var responses = from r in db.Responses
from rp in r.ResponseProperties
select new
{
RespondentID = r.RespondentID,
QuestionCode = r.Question.Code,
ResponseOptionCode = r.ResponseOption.Code,
ResponseOptionCodeName = r.ResponseOption.Text,
ResponsePropertyName = rp.Name,
ResponsePropertyTypeName = rp.ResponsePropertyType.Name
};
To clarify, you are trying to do this with LINQ to SQL and not EF as they have rather different models for M-M. With LINQ to SQL, you do have to include the middle join table.
The key thing missing from your query at this point is the filter (Where) clauses. You need to specify them for both sides of the join to properly filter the results. You indicate that when you supply a filter you get back no records. Can you clarify your question with that filter as it may help to fix your underlying problem.
Your query cannot produce unique responses because you also get ResponsePropertyName and ResponsePropertyTypeName, which will duplicate the results.
This entity framework query -
from r in db.Responses
where r.ResponseProperties.Any (rp => rp.Name == "USA")
where r.ResponseProperties.Any (rp => rp.Name == "Wave2012")
select new
{
RespondentID = r.RespondentID,
QuestionCode = r.Question.Code,
ResponseOptionCode = r.ResponseOption.Code,
ResponseOptionCodeName = r.ResponseOption.Text,
};
does produce unique Responses that are in USA and in Wave2012. The produced sql will show two EXISTS predicates with AND.
This is an efficiency/best practice question. Hoping to receive some feed back on performance. Any advice is greatly appreciated.
So here is a little background in what i have setup. I'm using codeigniter, the basic setup is pretty similar to any other product relationships. Basic tables are: Brands, products, categories. On top of these tables there is a need for install sheets, marketing materials, and colors.
I created some relationship tables:
Brands_Products
Products_Colors
Products_Images
Products_Sheets
I also have a Categories_Relationships table that holds all of the relationships to categories. Install sheets etc can have their own categories but i didn't want to define a different category relationship table for each type because i didn't think that would be very expandable.
On the front end I am sorting by brands, and categories.
I think that covers the background now to the efficiency part. I guess my question pertains mostly to weather it would be better to use joins or to make separate calls to return individual parts of each item (colors, images, etc)
What I currently have coded is working, and sorting fine but I think i can improve the performance, as it take some time to return the query. Right now its returning about 45 items. Here is my first function it grabs all the products and its info.
It works by first selecting all the products and joining it's brand information. then looping through the result i set up the basic information, but for the categories images and installs i am using functions that returns each of respected items.
public function all()
{
$q = $this->db
->select('*')
->from('Products')
->join('Brands_Products', 'Brands_Products.product_id = Products.id')
->join('Brands', 'Brands.id = Brands_Products.brand_id')
->get();
foreach($q->result() as $row)
{
// Set Regular Data
$data['Id'] = $row->product_id;
$data['Name'] = $row->product_name;
$data['Description'] = $row->description;
$data['Brand'] = $row->brand_name;
$data['Category'] = $this->categories($row->product_id);
$data['Product_Images'] = $this->product_images($row->product_id);
$data['Product_Installs'] = $this->product_installs($row->product_id);
$data['Slug'] = $row->slug;
// Set new item in return object with created data
$r[] = (object)$data;
}
return $r;
}
Here is an example of one of the functions used to get the individual parts.
private function product_installs($id)
{
// Select Install Images
$install_images = $this->db
->select('*')
->where('product_id', $id)
->from('Products_Installs')
->join('Files', 'Files.id = Products_Installs.file_id')
->get();
// Add categories to category object
foreach($install_images->result() as $pImage)
{
$data[] = array(
'id' => $pImage->file_id,
'src' => $pImage->src,
'title' => $pImage->title,
'alt' => $pImage->alt
);
}
// Make sure data exists
if(!isset($data))
{
$data = array();
}
return $data;
}
So again really just looking on advice on what is the most efficient, best practice way of doing this. I really appreciate any advice, or information.
I think your approach is correct. There are only a couple of options: 1) load your product list first, then loop, and load required data for each product row. 2) create a big join on all tables first, then loop through (possibly massive) cartesian product. The second might get rather ugly to parse. For example, if you got Product A and Product B, and Product A has Install 1, Install 2, Install 3, and product B has Install 1, and Install 2,t hen your result is
Product A Install 1
Product A Install 2
Product A Install 3
Product B Install 1
Product B Install 2
Now, add your images and categories to the join and it might become huge.
I am not sure what the sizes of your tables are but returning 45 rows shouldn't take long. The obvious thing to ensure (and you probably did that already) is that product_id is indexed in all tables as well as your brands_products tables and others. Otherwise, you'll do a table scan.
The next question is how you're displaying your data on the screen. So you're getting all products. Do you need to load categories, images, installs when you're getting a list of products? If you're simply listing products on the screen, you might want to wait to load that data until user picks a products they are viewing.
On a side note, any reason you're converting your array to object
$r[] = (object)$data;
Also, in the second function, you can simply add
$data = array();
before the foreach, instead of
// Make sure data exists
if(!isset($data))
{
$data = array();
}
You can try this:
Query all of the products
Get all of the product IDs from step 1
Query all of the install images that has a product ID from step 2, sorted by product ID
Iterate through the products from step 1, and add the results from step 3
That takes you from 46 queries (for 45 products) to 2 queries, without any additional joins.
You can also use CodeIgniter's Query Caching to increase performance even further, if it's worth the time to write the code to reset the cache when data is updated.
Doing more work in PHP is generally better than doing the work in MySQL in terms of scalability. You can scale PHP easily with load balancers and web servers. Scaling MySQL isn't as easy due to concurrency issues.