Is it possible to merge two simple DB queries to get a single reply containing a hash - postgresql

in my blog-like app, i have two separate queries;
Select id, title, content from posts where id ='$a_post_id'
and
Select tagname, tagscore from tags where postid ='$a_post_id'
Since my db is hosted on a different server from my app, my major performance issue is with the server request roudabout for both the queries.
I was wondering if I can merge the two queries into a single query so that the expected output is
postdetails for '$a_post_id'= id, title, content, tags (hash of tagname, tagscore)
Something similar to a join but where the rows are asymmetrical. Or join returning hashes...
Also, this sounds like a great fix to a simple issue, but am I missing something here? Assuming that this solution is possible, are there any obvioud cons associated with it?

If a JSON key/value pair is OK, you can something like this:
select p.id, p.title, p.content,
jsonb_object_agg(t.tagname, t.tagscore) as tags
from posts p
left join tags t on t.postid = p.id
where p.id ='$a_post_id'
group by p.id;
The above assumes that posts.id is defined as the primary key
Online example: https://rextester.com/RDQX27041

Related

How to speed up this Postgres query by reducing the number of rows it has to search through before it searches?

Context:
I have three Postgres tables:
authors - stores the id, author's full name, credentials, and awards
books - stores the id, title, book-length, summary, and an image of the front cover
authorBookRelations - connects Authors and Books by storing the author_id and book_id
An author can be connected to any book, but books are not connected. Books can have the same name, but each has its own id that is unique. Multiple authors can author a single book.
My question:
If I want to get all titles that match a given list of titles and are by a specific author what would be the best way to do that?
What I have so far:
Currently, I do two SELECT queries and a filtering function to "join" the two queries.
SELECT query #1 - get all of the book_ids associated with a particular author:
SELECT book_id FROM authorBookRelations WHERE author_id = 5
SELECT query #2 - get all of the titles that are in a given list of titles:
SELECT * FROM books WHERE title IN ('arbitraryTitle_1', arbitraryTitle_2, etc.)
Filter function (python) - filter titles for any that are not written by that specific author:
filtered_list = [x for x in query_2_results if x.id in query_1_results]
I get the correct books with this method, but can't help but feel that this is not a good way to do it/won't scale well. What would you suggest as a way to speed up this query? Instead of two separate db calls and a filtering function, could I do it all in one call by searching the list of titles against the filtered rows in table "books" that were filtered by the output from the query against authorBookRelations? ... that was horribly worded ... so something like this:
SELECT *
FROM (
SELECT book_id
FROM authorBookRelations
WHERE author_id = 5) AS foobar
WHERE title IN ('arbitraryTitle_1', arbitraryTitle_2, etc.)
UPDATE:
Trying out this seems to have cut my total query/processing time by half:
select *
from (select *
from books
where id in (
select book_id
from authorBookRelations
where author_id = 5
)) as foo
where foo.title in ('arbitraryTitle_1', 'arbitraryTitle_2', etc.)
The problem of performances will be on the "IN" operator, if the list has a great number of items...
For two or three sometime an index can be used by PG for seeking the data.
But when there is much more items, a scan will be the only solution...
If you want to speed up this query, just use a temporary table to INSERT your data into, the add an index and rewrite the query with a join between this temp table and your original query...

Get entire record with max field for each group

There are a lot of answers about this problem, but none of them retrieves the entire record, but only the ID... and I need the whole record.
So, I have a table status_changes that is composed of 4 columns:
issue_id : the issue the change refers to
id: the id of the change, just a SERIAL
status_from and status_to that are infact the status that the issue had before, and the status that the issue got then
when that is a timestamp of when this happened
Nothing too crazy, but now, I would like to have the "most recent status_change" for each issue.
I tried something like:
select id
from change
group by issue_id
having when = max(when)
But this has obviously 2 big problems:
select contains fields that are not in the group by
2 having can't contains aggregate function in this way
I thought of "ordering every group by when and using something like top(1), but I can't figure out how to do it...
Use PostgreSQL's DISTINCT ON:
SELECT DISTINCT ON (issue_id)
id, issue_id, status_from, statue_to, when
FROM change
ORDER BY issue_id, when DESC;
This will return the first result (the one with the greatest when) for each issue.

How to perform Model Joins + Condition on Relations in Sails.js?

How can I make a model join query(condition) and sort on relation models on Sails?
Example: I have 4 tables(collections in mongodb) and 4 related models in mongodb:
User: user_id, name
Follow: user_id, following_id (user id is being followed)
Point: user_id, point
Post: name, content, user_id, created_at
So from the post table, I want to make a query to find the posts of users that I'm following and sort by their point. Like this raw sql:
SELECT post.* FROM post
LEFT JOIN user_point up ON up.user_id = post.user_id
WHERE post.user_id IN (1,2,3,4) // assume I got my following_user_ids result is 1,2,3,4 for this case so no need to join follow table
ORDER BY up.point DESC // high point then first return
I don't know how can do this by Sails model? I have read many instructions by got no helps. Almost people said: Sails Association, but it just helps return the relation instead of do the where or order by to sort original model results(is this case: post).
I have worked with Yii2, a PHP framework so with this case I can do it easily:
Post::model()->leftJoin('user_point up', 'up.user_id = post.user_id')->where(['post.user_id' => [1,2,3,4])->orderBy(['up.point' => SORT_DESC])->all();
I'm stucked in Sails, very thanks if someone help me!!!
Because you're using Mongo, and because you need the full power of normal JOIN's, you will probably be forced to use some other ORM solution (i.e. mongodb package on npm) for queries like that.
Why? See the API documentation for sendNativeQuery(), which states native query features are only available for SQL-like DBMS's.

OrientDB query for nodes connected to origin by multiple ways

For example, I have employee managing particular country and particular company. I want to query only accounts which are in countries AND companies managed by the given employee. Ideas? Performance issues to be aware of?
Gremlin query is acceptable, also!
This seems to work:
select from Account where
#rId in
(select expand(out('managingCountry').in('inCountry')).#rId
from Employee where userId = 3)
AND
#rId in
(select expand(out('managingCompany').in('inCompany')).#rId
from Employee where userId = 3)
Remains if someone has the better solution

products and configurable_products in postgresql

I have a Product table and a ConfigurableProduct table.
If there are several variations of the same product like a shirt in different colors I create a ConfigurableProduct.
When a user is looking at the catalog he should see a list of products unless there is a ConfigurableProduct, then he should see it with a select box for each variations.
How do I structure the tables for Product and ConfigurableProduct and how do I query the db so I can page through the results?
Thanks
I am going to answer this as if you do not have tables created. I am not sure if that is true though.
The following is a simple example, but I assume you have more data.
products
id
name
configurable_products
id
variation
product_id REFERENCES products(id)
You can just make the configurable products a reference to products.
If you want a listing of products with their configurations then you can do:
select p.name, c.variation
from products p left outer join configurable_products c
on (p.id = c.product_id);
Of course you can just search for all the configurable_products based on the product id too when needed.
As for the paging part of your question you will have to clarify what you mean. You can use limit to limit results if you don't want to get everything at once.