Optimize SQL query that retrieves count of items over a period - sql

Is there a way to better optimize the query in this function? I am wanting it to only make a single SQL query if possible. The code picks up the number of events generated over 2 weeks. Thanks.
def items_chart_data
#current_student = Student.find(current_user.student_id)
(2.weeks.ago.to_date..DateTime.now).map do |date|
{
created_at: date,
item_count: Item.where("date(created_at) = ? AND student_id = ?", date, #current_student.id).count
}
end
end

You can do it in one query, like this:
items = Item.select('date(created_at) as date_created, count(id) as id_count').
where('student_id = ? and created_at >= ?', current_user.student_id, 2.weeks.ago.beginning_of_day).
group('date(created_at)').map do |item|
{ created_at: item.date_created, item_count: item.id_count }
end
To get the missing dates with 0 items into your array you can do this:
(2.weeks.ago.to_date..Date.current).each do |date|
date = date.strftime('%Y-%m-%d')
unless items.any? { |h| h.value?(date) } # Check if date exists already
items << { created_at: date, item_count: 0 } # Add item_count: 0 if not
end
end
items.sort_by! { |h| h[:created_at] } # Put array in correct order
Note that adding the zero item days to the array doesn't perform any queries. The array items contains only 14 elements, so (especially compared to querying the database 14 times) this code should be really fast.

Related

Dynamic column search in multiple tables with gorm golang

My scenario is i have a grid with search option where user can select the column and can do the search, the grid data is coming from various tables. I have attached a sample screen of grid.
User Screen
So i'm trying to create a dynamic query for search but the problem is i can able to search only in main table (schema.Robot) not in Preload tables. whenever i trying to search data data from Preload tables let say from RobotModel table that time getting below error
pq: missing FROM-clause entry for table "robot_models"
Here is my go code
func (r *RobotsRepository) GetRobotsSummary(listParams viewmodel.ListParams, companyID uint) ([]*schema.Robot, int, error) {
mrobots := []*schema.Robot{}
var count int
var order string
if listParams.SortColumn == "" {
listParams.SortColumn = "id"
listParams.SortOrder = 1
} else {
listParams.SortColumn = util.Underscore(listParams.SortColumn)
}
if listParams.SortOrder == 0 {
order = "ASC"
} else {
order = "DESC"
}
var searchQuery string
if listParams.SearchText != "" {
switch listParams.SearchColumn {
case "Robot":
listParams.SearchColumn = "name"
case "Model":
listParams.SearchColumn = "robot_models.name"
}
searchQuery = listParams.SearchColumn +" LIKE '%"+ listParams.SearchText +"%' and Company_ID = " + fmt.Sprint(companyID)
}else{
searchQuery = "Company_ID = " + fmt.Sprint(companyID)
}
orderBy := fmt.Sprintf("%s %s", listParams.SortColumn, order)
err := r.Conn.
Preload("RobotModel", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Name")
}).
Preload("Task", func(db *gorm.DB) *gorm.DB {
return db.Where("Task_Status in ('In-Progress','Pending')").Select("ID, Task_Status")
}).
Preload("CreatedUser", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Display_Name")
}).
Preload("UpdatedUser", func(db *gorm.DB) *gorm.DB {
return db.Select("ID,Display_Name")
}).
Where(searchQuery).
Order(orderBy).
Offset(listParams.PageSize * (listParams.PageNo - 1)).
Limit(listParams.PageSize).
Find(&mrobots).Error
r.Conn.Model(&schema.Robot{}).Where(searchQuery).Count(&count)
return mrobots, count, err
}
In searchQuery variable i'm storing my dynamic query.
My question is how can i search data for preload table columns
Here is the sql query which i'm trying to achieve using gorm
SELECT robots.id,robots.name,robot_models.name as
model_name,count(tasks.task_status) as task_on_hand,
robots.updated_at,users.user_name as updated_by
FROM rfm.robots as robots
left join rfm.tasks as tasks on tasks.robot_id = robots.id and
tasks.task_status in ('In-Progress','Pending')
left join rfm.robot_models as robot_models on robot_models.id =
robots.robot_model_id
left join rfm.users as users on users.id = robots.updated_by
WHERE robot_models.name::varchar like '%RNR%' and robots.deleted_at is null
GROUP BY robots.id,robot_models.name,users.user_name
ORDER BY task_on_hand DESC LIMIT 2 OFFSET 0
and sorry for bad English!
Even though you are preloading, you are still required to explicitly use joins when filtering and ordering on columns on other tables. Preloading is used to eagerly load the data to map into your models, not to join tables.
Chain on something like this:
.Joins("LEFT JOIN rfm.robot_models AS robot_models ON robot_models.id = robots.robot_model_id")
I'm not positive if you can use the AS keyword using this technique, but if not, it should be easy enough to adjust your query accordingly.

Grails sub query with createCriteria

I have sql query like below
select transf, count(fname) from peak_info where fname in (select peakfile from pe_result where conid = 'GO:0006007' and fdr > 0.05) group by transf;
which I want to implement in grails create criteria. Currently, I am running the SQL query in bracket first and then run an outer query like below:
def test2 = PeResult.createCriteria()
def ptest=test2.list {
eq("conid",conid.toString())
gt("fdr","0.05")
}
def peaknames = ptest.peakfile
def peakinfoFilter = PeakInfo.createCriteria()
def pifilter = peakinfoFilter.list {
'in'("fname", peaknames)

projections
{
groupProperty "transF"
count "fname"
}

}
I was wondering if there are other ways doing this into one query instead of running two queries?
You probably can do something like this. Haven’t executed it but you got the idea. Have a look at subquery section of GORM.
def peakinfoFilter = PeakInfo.createCriteria()
def pifilter = peakinfoFilter.list {
'in' "fname", PeResult.where{
conid == conid.toString()
fdr > "0.05"
}. peakfile
projections
{
groupProperty "transF"
count "fname"
}
}

Grails: "where" query with optional associations

I'm trying to run a "where" query to find a domain model object that has no association with another domain model object or if it does, that domain model object has a specific property value. Here's my code:
query = Model.where({
other == null || other.something == value
})
def list = query.list()
However, the resulting list only contains objects that match the second part of the OR statement. It contains no results that match the "other == null" part. My guess is that since it's checking a value in the associated object its forcing it to only check entries that actually have this associated object. If that is the case, how do I go about creating this query and actually having it work correctly?
You have to use a LEFT JOIN in order to look for null associations. By default Grails uses inner join which will not be joined for null results. Using withCriteria as below you should get the expected results:
import org.hibernate.criterion.CriteriaSpecification
def results = Model.withCriteria {
other(CriteriaSpecification.LEFT_JOIN){
or{
isNull 'id'
eq 'something', value
}
}
}
UPDATE
I know aliasing is not possible in DetachedCritieria where one would try to specify the join as in createCriteria/withCriteria. There is an existing defect regarding adding the functionality to DetachedCriteria. Just adding the work around for where query as mentioned in defect.
Model.where {
other {
id == null || something == value
}
}.withPopulatedQuery(null, null){ query ->
query.#criteria.subcriteriaList[0].joinType = CriteriaSpecification.LEFT_JOIN
query.list()
}
I would rather use withCriteria instead of the above hack.
this might work:
query = Model.where({
isNull( other ) || other.something == value
})
If that wouldn't work, try something like:
other.id == null || other.something == value
UPDATE:
or with good'ol criteria query:
list = Pack.withCriteria{
or{
isNull 'other'
other{ eq 'something', value }
}
}

Raven query returns 0 results for collection contains

I have a basic schema
Post {
Labels: [
{ Text: "Mine" }
{ Text: "Incomplete" }
]
}
And I am querying raven, to ask for all posts with BOTH "Mine" and "Incomplete" labels.
queryable.Where(candidate => candidate.Labels.Any(label => label.Text == "Mine"))
.Where(candidate => candidate.Labels.Any(label => label.Text == "Incomplete"));
This results in a raven query (from Raven server console)
Query: (Labels,Text:Incomplete) AND (Labels,Text:Mine)
Time: 3 ms
Index: Temp/XWrlnFBeq8ENRd2SCCVqUQ==
Results: 0 returned out of 0 total.
Why is this? If I query for JUST containing "Incomplete", I get 1 result.
If I query for JUST containing "Mine", I get the same result - so WHY where I query for them both, I get 0 results?
EDIT:
Ok - so I got a little further. The 'automatically generated index' looks like this
from doc in docs.FeedAnnouncements
from docLabelsItem in ((IEnumerable<dynamic>)doc.Labels).DefaultIfEmpty()
select new { CreationDate = doc.CreationDate, Labels_Text = docLabelsItem.Text }
So, I THINK the query was basically testing the SAME label for 2 different values. Bad.
I changed it to this:
from doc in docs.FeedAnnouncements
from docLabelsItem1 in ((IEnumerable<dynamic>)doc.Labels).DefaultIfEmpty()
from docLabelsItem2 in ((IEnumerable<dynamic>)doc.Labels).DefaultIfEmpty()
select new { CreationDate = doc.CreationDate, Labels1_Text = docLabelsItem1.Text, Labels2_Text = docLabelsItem2.Text }
Now my query (in Raven Studio) Labels1_Text:Mine AND Labels2_Text:Incomplete WORKS!
But, how do I address these phantom fields (Labels1_Text and Labels2_Text) when querying from Linq?
Adam,
You got the reason right. The default index would generate 2 index entries, and your query is executing on a single index entry.
What you want is to either use intersection, or create your own index like this:
from doc in docs.FeedAnnouncements
select new { Labels_Text = doc.Labels.Select(x=>x.Text)}
And that would give you all the label's text in a single index entry, which you can execute a query on.

How to get count of all items in a criteria GORM query

So i have this criteria query that is getting 10 feature articles that have itemchannel objects that are of type 4 and in a channel of id 1 i.e get me top 10 articles which are of type feature and in channel x.
def criteria = Feature.createCriteria()
list = criteria.list {
maxResults(params.max)
itemChannels {
eq ('itemType.id',(long)4)
eq ('channel.id',(long)1)
}
}
How do i get the total count efficiently i.e. i have the articles for page 1 but i need the total number for pagination?
Thanks
Think i sorted this.
criteria = Feature.createCriteria()
count = criteria.get{
projections {
countDistinct('id')
}
itemChannels {
eq ('itemType.id',(long)4)
eq ('channel.id',(long)2)
}
}