Sequelize Average of Date Difference - sql

I have the following (abstract) sequelize model:
{
startTime: Date,
endTime: Date,
}
Now I want to get the average duration of all existing entities. In SQL I'd model this like SELECT AVG("end_time" - "start_time") FROM "MyTable";. But I don't know how I can do this with sequelize.
I've made some attempts on using sequelize.fn() but did not come to a conclusion.
So my goal is to have something like:
MyModel.findAll({
attributes: ['averageTime' <<< now what?]
});
Oh and I'm using PostgreSQL 9.6.
Best,
Philipp

You can't use findAll or findOne as they return instance(s) of the model and you need to get some scalar value.
Raw query can be used to do what you need like this:
sequelize.query(
'SELECT AVG("end_time" - "start_time") FROM "MyTable"',
{ type: sequelize.QueryTypes.SELECT}
).then(function(result) {
// process result here
})

Related

How to use a function in select along with all the records in Sequalize?

Here is a Sequalize query below which retrieves a transformed value based on the table column value.
courses.findAll({
attributes: [ [sequelize.fn('to_char', sequelize.col('session_date'), 'Day'), 'days']]
});
The above sequlaize query will return result equal to as followed SQL query.
select to_char(bs.session_date, 'Day') as days from courses bs;
Expected output:
I want the transformed value which is in attributes along with all records like below. I know we can mention all the column names in attributes array but it is a tedious job. Any shortcut similar to asterisk in SQL query.
select to_char(bs.session_date, 'Day') as days,* from courses bs;
I tried the below sequalize query but no luck.
courses.findAll({
attributes: [ [sequelize.fn('to_char', sequelize.col('session_date'), 'Day'), 'days'],'*']
});
The attributes option can be passed an object as well as an array of fields for finer tuning in situations like this. It's briefly addressed in the documentation.
courses.findAll({
attributes: {
include: [
[ sequelize.fn('to_char', sequelize.col('session_date'), 'Day'), 'days' ]
]
}
});
By using include we're adding fields to the courses.* selection. Likewise we can also include an exclude parameter in the attributes object which will remove fields from the courses.* selection.
There is one shortcut to achieve the asterisk kind of selection in Sequalize. Which can be done as follows...
// To get all the column names in an array
let attributes = Object.keys(yourModel.rawAttributes);
courses.findAll({
attributes: [...attributes ,
[sequelize.fn('to_char', sequelize.col('session_date'), 'Day'), 'days']]
});
This is a work around there may be a different option.

Query items of a collection before a certain date on Fauna Db?

I looked on google and tried different thing but I cannot figure out how to query all the item of a collection that have the key dueDate before the a certain Date.
On Mysql I would do something like :
select * from table_name where dueDate < "2001-01-01 00:00:00"
That query on mysql would return the items with the Date Inferior to 2001-01-01
I tried to do use that query on Fauna :
q.Map(
q.Paginate(
q.Match(q.Index(indexesQuery1)),
{ before: Date('2021-01-15T17:34:00+08:00')
} ),
q.Lambda("X", q.Get(q.Var("X"))) ) )
indexQuery1 is : getNewWordDemoIso(dueDate: Date!)
But It returns an empty Array,
Also I saved all my Date all Fauna the date format called : iso 8601
Also Im using javascript
Any ideas !?
thanks !!
When you perform an "Create", you need parse your ISOString Date for an FaunaDB Date format.
You migth need something like this:
const newTransaction = await fauna.query<TransactionObject>(
q.Create(q.Collection("transactions"), {
data: {
...transaction,
firstDueDate: q.Date(transaction.firstDueDate),
lastDueDate: q.Date(transaction.lastDueDate),
createdAt: q.ToDate(q.Now())
}
})
);
This will work for you as you said you are using JS/TS.
ps: (import {query as q} from 'faunadb')

SQL Query to JSONiq Query

I want to convert an SQL query into a JSONiq Query, is there already an implementation for this, if not, what do I need to know to be able to create a program that can do this ?
I am not aware of an implementation, however, it is technically feasible and straightforward. JSONiq has 90% of its DNA coming from XQuery, which itself was partly designed by people involved in SQL as well.
From a data model perspective, a table is mapped to a collection and each row of the table is mapped to a flat JSON object, i.e., all fields are atomic values, like so:
{
"Name" : "Turing",
"First" : "Alan",
"Job" : "Inventor"
}
Then, the mapping is done by converting SELECT-FROM-WHERE queries to FLWOR expressions, which provide a superset of SQL's functionality.
For example:
SELECT Name, First
FROM people
WHERE Job = "Inventor"
Can be mapped to:
for $person in collection("people")
where $person.job eq "Inventor"
return project($person, ("Name", "First"))
More complicated queries can also be mapped quite straight-forwardly:
SELECT Name, COUNT(*)
FROM people
WHERE Job = "Inventor"
GROUP BY Name
HAVING COUNT(*) >= 2
to:
for $person in collection("people")
where $person.job eq "Inventor"
group by $name := $person.name
where count($person) ge 2
return {
name: $name,
count: count($person)
}
Actually, if for had been called from and return had been called select, and if these keywords were written uppercase, the syntax of JSONiq would be very similar to that of SQL: it's only cosmetics.

Summation of sub document field based on a group unexpected behaviour

*I have a document structured in which we embedded the salary Document into the Employee_Detail Document.As per the MongoDb documantation ,we can use $Unwind to deconstruct the Document and use aggregated pipeline...But its not working. i am using the below script...*
{
"_id" : ObjectId("5763d4a54da83b98f269878a"),
"First_Name" : "fgfg",
"Department" : "QA",
"Salary" : {
"HRA" : "1200",
"Basic" : "2000",
}
})
And i want to get sum of basic salary based on department Like
then Expected output is
Department Total_Basic**
QA 2000
I have used the following code to get the output. I have used the $unwind to deconstruct the document.and use aggregated pipeline to group the department(Sum of basic Salary).
db.Employee_Detail.aggregate([
{$unwind:"$Salary"}, {$group: {"_id": "$Department", total_Basic: {$sum: "$Salary.Basic" }
}}
])
But i get the below Result.
Department Total_Basic
QA 0
I think $unwind is not Working. Please suggest
Your main problem is the type of the field Basic is a string. Second, you do not need to use unwind unless the field Salary contains an array.
So perform an update to convert the types of Basic and HRA to floats, (see this stackoverflow question)
And then an aggregate operation like this will give you the desired result:
db.Employee_Detail.aggregate([
{$group: {"_id": "$Department", total_Basic: {$sum: "$Salary.Basic" }}
])

Setting group_by in specialized query

I need to perform data smoothing using averaging, with a non-standard group_by variable that is created on-the-fly. My model consists of two tables:
class WthrStn(models.Model):
name=models.CharField(max_length=64, error_messages=MOD_ERR_MSGS)
owner_email=models.EmailField('Contact email')
location_city=models.CharField(max_length=32, blank=True)
location_state=models.CharField(max_length=32, blank=True)
...
class WthrData(models.Model):
stn=models.ForeignKey(WthrStn)
date=models.DateField()
time=models.TimeField()
temptr_out=models.DecimalField(max_digits=5, decimal_places=2)
temptr_in=models.DecimalField(max_digits=5, decimal_places=2)
class Meta:
ordering = ['-date','-time']
unique_together = (("date", "time", "stn"),)
The data in WthrData table are entered from an xml file in variable time increments, currently 15 or 30 minutes, but that could vary and change over time. There are >20000 records in that table. I want to provide an option to display the data smoothed to variable time units, e.g. 30 minutes, 1, 2 or N hours (60, 120, 180, etc minutes)
I am using SQLIte3 as the DB engine. I tested the following sql, which proved quite adequate to perform the smoothing in 'bins' of N-minutes duration:
select id, date, time, 24*60*julianday(datetime(date || time))/N jsec, avg(temptr_out)
as temptr_out, avg(temptr_in) as temptr_in, avg(barom_mmhg) as barom_mmhg,
avg(wind_mph) as wind_mph, avg(wind_dir) as wind_dir, avg(humid_pct) as humid_pct,
avg(rain_in) as rain_in, avg(rain_rate) as rain_rate,
datetime(avg(julianday(datetime(date || time)))) as avg_date from wthr_wthrdata where
stn_id=19 group by round(jsec,0) order by stn_id,date,time;
Note I create an output variable 'jsec' using the SQLite3 function 'julianday', which returns number of days in the integer part and fraction of day in the decimal part. So, multiplying by 24*60 gives me number of minutes. Dividing by N-minute resolution gives me a nice 'group by' variable, compensating for varying time increments of the raw data.
How can I implement this in Django? I have tried the objects.raw(), but that returns a RawQuerySet, not a QuerySet to the view, so I get error messages from the html template:
</p>
Number of data entries: {{ valid_form|length }}
</p>
I have tried using a standard Query, with code like this:
wthrdta=WthrData.objects.all()
wthrdta.extra(select={'jsec':'24*60*julianday(datetime(date || time))/{}'.format(n)})
wthrdta.extra(select = {'temptr_out':'avg(temptr_out)',
'temptr_in':'avg(temptr_in)',
'barom_mmhg':'avg(barom_mmhg)',
'wind_mph':'avg(wind_mph)',
'wind_dir':'avg(wind_dir)',
'humid_pct':'avg(humid_pct)',
'rain_in':'avg(rain_in)',
'rain_sum_in':'sum(rain_in)',
'rain_rate':'avg(rain_rate)',
'avg_date':'datetime(avg(julianday(datetime(date || time))))'})
Note that here I use the sql-avg functions instead of using the django aggregate() or annotate(). This seems to generate correct sql code, but I cant seem to get the group_by set properly to my jsec data that is created at the top.
Any suggestions for how to approach this? All I really need is to have the QuerySet.raw() method return a QuerySet, or something that can be converted to a QuerySet instead of RawQuerySet. I can not find an easy way to do that.
The answer to this turns out to be really simple, using a hint I found from
[https://gist.github.com/carymrobbins/8477219][1]
though I modified his code slightly. To return a QuerySet from a RawQuerySet, all I did was add to my models.py file, right above the WthrData class definition:
class MyManager(models.Manager):
def raw_as_qs(self, raw_query, params=()):
"""Execute a raw query and return a QuerySet. The first column in the
result set must be the id field for the model.
:type raw_query: str | unicode
:type params: tuple[T] | dict[str | unicode, T]
:rtype: django.db.models.query.QuerySet
"""
cursor = connection.cursor()
try:
cursor.execute(raw_query, params)
return self.filter(id__in=(x[0] for x in cursor))
finally:
cursor.close()
Then in my class definition for WthrData:
class WthrData(models.Model):
objects=MyManager()
......
and later in the WthrData class:
def get_smoothWthrData(stn_id,n):
sqlcode='select id, date, time, 24*60*julianday(datetime(date || time))/%s jsec, avg(temptr_out) as temptr_out, avg(temptr_in) as temptr_in, avg(barom_mmhg) as barom_mmhg, avg(wind_mph) as wind_mph, avg(wind_dir) as wind_dir, avg(humid_pct) as humid_pct, avg(rain_in) as rain_in, avg(rain_rate) as rain_rate, datetime(avg(julianday(datetime(date || time)))) as avg_date from wthr_wthrdata where stn_id=%s group by round(jsec,0) order by stn_id,date,time;'
return WthrData.objects.raw_as_qs(sqlcode,[n,stn_id]);
This allows me to grab results from the highly populated WthrData table smoothed over time increments, and the results come back as a QuerySet instead of RawQuerySet