using like clause with peewee.Model.get method - peewee

class SomeModel(peewee.Model):
date_time_added = peewee.DateTimeField()
date_time_added row contains datetime in the format "12-02-1982 18:12:22" format
i can get by building the select query
SomeModel.select(SomeModel.date_added).where(SomeModel.date_time_added.startswith("12-02-1982"))
how do I get time with specific date using get method of peewee.Model
SomeModel.get

First off I'd like to strongly advise against using that format. Why? It doesn't sort properly. If you use YYYY-mm-dd HH:MM:SS then you can do sorts and range scans and the results will actually be sensible.
With .get() you would:
obj = SomeModel.get(SomeModel.date_time_added.startswith('12-02-1982'))
Or alternatively:
query = SomeModel.select(SomeModel.date_added).where(SomeModel.date_time_added.startswith('12-02-1982'))
obj = query.get()

Related

Django query bases on greater date

I want to know how efficient this filter can be done with django queries. Essentially I have the followig two clases
class Act(models.Model):
Date = models.DateTimeField()
Doc = models.ForeignKey(Doc)
...
class Doc(models.Model):
...
so one Doc can have severals Acts, and for each Doc I want to get the act with the greater Date. I'm only interested in Acts objects.
For example, if a have
act1 = (Date=2021-01-01, Doc=doc1)
act2 = (Date=2021-01-02, Doc=doc1)
act3 = (Date=2021-01-03, Doc=doc2)
act4 = (Date=2021-01-04, Doc=doc2)
act5 = (Date=2021-01-05, Doc=doc2)
I want to get [act2, act5] (the Act with Doc=doc1 with the greater Date and the Act with Doc=doc2 with the greater Date).
My only solution is to make a for over Docs.
Thank you so much
You can do this with one or two queries: the first query will retrieve the latest Act per Doc, and then the second one will then retrieve the acts:
from django.db.models import OuterRef, Subquery
last_acts = Doc.objects.annotate(
latest_act=Subquery(
Act.objects.filter(
Doc_id=OuterRef('pk')
).values('pk').order_by('-Date')[:1]
)
).values('latest_act')
and then we can retrieve the corresponding Acts:
Act.objects.filter(pk__in=last_acts)
depending on the database, it might be more efficient to first retrieve the primary keys, and then make an extra query:
Act.objects.filter(pk__in=list(last_acts))

Firebase pagination using a timestamp/date as the orderBy

I am struggling to get pagination working when I use a date (firebase timestamp) to retrieve data.
This is basically what I do:
let jobsRef = db.collection("jobs")
.orderBy('createdAt', 'desc')
.limit(QUERY_LIMIT);
jobsRef = jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1].createdAt);
However it seems that i get returned items sometimes that I have just already received. I am guessing because of similar dates?
So how could I basically return a list of jobs ordered by createdAt and have an offset/limit (pagination)?
createdAt looks like the timestamp type: 23 October 2020 at 17:26:31 UTC+2
When I log createdAt however I see this: {seconds: 1603537477, nanoseconds: 411000000}
Maybe I should be storing createdAt as a unix timestamp? Or what is the ideal way to deal with this?
Here is how it looks in the database (popup when i click edit on createdAt):
If multiple documents can have the same value for the field you're sorting on, passing in a value for that field is not guaranteed to point to a unique document. So you indeed may be passing in an ambiguous instruction, leading to an unwanted result.
When possible, I highly recommend passing the entire document to the Firestore API. This leaves it up to Firestore to take the necessary data from that document to uniquely/unambiguously find the anchor for your query.
So instead of:
jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1].createdAt);
Do:
jobsRef.startAfter(this.props.jobs[this.props.jobs.length - 1]);
I was facings a similar problem, after may hours I finally found a solution, all you need to do is converting that number to firestore's Timestamp
import { Timestamp }. from #angular/fire/firestore;
let createdAt: number = 56772766688383;
let timestamp = Timestamp.fromMillis(createdAt);
//then pass that to startAfter
startAfter(timestamp)

How to use mongodb aggregate functions in Criteria?

I am working on a project where I use spring data mongodb. I am making a mongo query like this:
Query query = new Query();
Criteria one = Criteria.where(DB_FIELD_1).gt(1);
Criteria two = Criteria.where(DB_FIELD_2).lt(10);
Criteria final = new Criteria().andOperator(one,two);
query.addCriteria(final);
// after making the query, I am executing it using mongoTemplate
Now, I have a Date field with format YYYYMMDD. I would like to check if its month = current month. For example, if the field is 20170501, then the date's month (05) is current month (5, May). How do I extract the month value from date and check this logic along with other criteria above ( one and two )? I know there is $month to extract the month value from date. But, I do not know how to incorporate aggregate function within "Criteria" class. My final result should be something like this:
Criteria final = new Criteria().andOperator(one,two,criteria to check month = current month);
query.addCriteria(final);
You can use below aggregation pipeline with the current spring db version 1.10.2/ Spring 1.5.2 Boot. Include the other fields in the $project that you wish to output.
Use $addFields instead of $project for 3.4 x mongo server version.
AggregationOperation project = Aggregation.project().and(DateOperators.dateOf(DB_FIELD_1).month()).as("field1").and(DateOperators.dateOf(DB_FIELD_2).month()).as("field2");
AggregationOperation match = Aggregation.match(Criteria.where("field1").gt(1)
.and("field2").lt(10));
Aggregation aggregation = Aggregation.newAggregation(project, match);
List<BasicDBObject> results = mongoTemplate.aggregate(aggregation, collectionname, BasicDBObject.class).getMappedResults();
Use for 1.4.1 version
AggregationOperation project = Aggregation.project().and(DB_FIELD_1).extractMonth().as("field1").and(DB_FIELD_2).extractMonth().as("field2");

Laravel Eloquent - Find average for a group of days in a month

i have 2 colums. One is datetime (imeromina_metrisis) and the other has integers (apotelesma). What i am trying to do is to get the average integer number for each day so that i can send it to a chart. Do you have any idea how can i do this?
This is my table here
We need to get DATE format first instead of using DATETIME since you need data for each day. Try this query
$data = DB::table('table_name')
->select(DB::raw('avg(apotelesma) as count, DATE(imeromina_metrisis) day'))
->groupBy('day')
->get();
refer how to select raw expression here
Probably something like this.
$avg = Model::where('imeromina_metreisis', $carbon)->avg('apotelesma');
See:
https://laravel.com/docs/5.1/queries#aggregates
Just be aware of your date column. $carbon is a variable representing the Carbon date and time object that Laravel uses extensively. If the average is for an entire day, but you're using datetime (which includes hours/minutes/seconds), you will want to do something like this.
$carbon = Carbon::now()->startOfDate();
$avg = Model::where('imeromina_metreisis', '>=', $carbon)
->where('imeromina_metreisis', '<=', $carbon->copy()->endOfDay())
->avg('apotelesma');
And yes, those are built-in Carbon methods. It really is a great library.
Edit: More documentation on Carbon. I think you want arbitrary day ranges.
http://carbon.nesbot.com/docs/
Ok I found the solution, by using Eloquent + Fluent, to be able to use my relationships. This is my code to get a collection of all my Articles + User + Rating average :
$articles = Articles::where('state', '=', '1')
->with('user')
->leftJoin('ratings', 'ratings.article_id', '=', 'articles.id')
->select(array('articles.*',
DB::raw('AVG(rating) as ratings_average')
))
->groupBy('id')
->orderBy('ratings_average', 'DESC')
->get();

Pass a DateTime[] as a SQL parameter for ObjectContext.ExecuteStoreCommand

I'm using ExecuteStoreCommand to facilitate bulk deletes.
This Works
// ExecuteStoreCommand syntax via http://stackoverflow.com/a/13024320/740639
// Delete all of today's events
DateTime eventDate = DateTime.Now;
string sql = "DELETE FROM EventCalendar WHERE EventDate = {0}";
context.ObjectContext.ExecuteStoreCommand(sql, new object[] { eventDate });
I want to do this, but it does not work
I get an ArgumentException: "No mapping exists from object type System.DateTime[] to a known managed provider native type."
// Delete all of the events for the past 3 days
DateTime[] eventDates = new DateTime[] {
DateTime.Now.AddDay(-1),
DateTime.Now.AddDay(-2),
DateTime.Now.AddDay(-3)
};
string sql = "DELETE FROM EventCalendar WHERE EventDate IN ({0})";
context.ObjectContext.ExecuteStoreCommand(sql, new object[] { eventDates });
Proposed Solution
I could convert my DateTime[] into the string "'2013-06-24', '2013-06-23', '2013-06-22'" and pass that as the parameter, but that seems like a hack.
I know there are libraries that add bulk delete support to EF, but I don't want to go that route at this time.
Any suggestions?
If you manipulate the string, every time you change the dates you will get a slightly different SQL statement. It may look the same, but the string is different and will have a different hash. So this subverts caching of the execution plan and kills performance.
You can't really pass parameters in an IN clause the way you're thinking. There are some other ideas in this post that might work, but if you read the notes they all say they have lousy performance.
If you can be assured that you will have a fixed number of inputs, you could use the technique of passing them as separate parameters:
... WHERE EventDate IN (#dt1, #dt2, #dt3)
Otherwise, I would go with an approach like Tom suggested, pass them as a delimited string and parse it on the server.
Also - since you are doing an exact match, you probably want to snap to midnight using DateTime.Today rather than DateTime.Now, or use the .Date property of an existing DateTime.
Here's another suggestion, if you really are just trying to delete for the last three days, why not do this?
string sql = "DELETE FROM EventCalendar WHERE EventDate BETWEEN {0} AND {1}";
context.ObjectContext.ExecuteStoreCommand(sql,
new object[] { DateTime.Today.AddDays(-3), DateTime.Today.AddDays(-1) });
Or with a bit of thought, you could probably just use sql getdate() and similar functions instead of passing parameters at all.
You could combine the dates with a delimiter on the .net side, pass it through as a paramter, and then use a Table-Valued function to split a delimited string on the server side.
Pass in something like "2013-06-24|2013-06-23|2013-06-22"
http://ole.michelsen.dk/blog/split-string-to-table-using-transact-sql/

Resources