AppSync - query for all items created within a date range? - elasticsearch

I'm trying to query my items (which have fields of AWS DateTime of CreatedAt and UpdatedAt) for all within a certain date range. For example, the past 48 hours.
For example, using this schema:
type Note #model #searchable #auth(rules: [{ allow: owner }]) {
id: ID!
note: String
createdAt: AWSDateTime
I'm able to search for dates using, for example:
query {
searchNotes(filter:{createdAt: { matchPhrasePrefix: "2018-12-27"}}) {
items{
id
title
createdAt
}
}
}
Which returns all notes that match the UTC time with that string prefix.
From which, I have to sort myself using moment.diff(), or some other method.
I'm not sure there is a better/more efficient way of doing searching/filtering by dates and time using AppSync and GraphQl?
Thank you.

You can use this query to filter 2 AWSDateTime:
query {
searchNotes(filter:{createdAt: { between: ["2018-12-27T00:00:00", "2019-01-27T00:00:00"]}}) {
items{
id
title
createdAt
}
}
}

As of writing (Jan 3, 2019), the easiest way to do this would be to store the date as an integer (e.g. seconds since epoch) which would open up the gt, lt, gte, ... filter fields on the auto-generated search resolvers filter input.
Another solution is to write your own resolver using the AWS AppSync console or your own CloudFormation stack. When writing your own resolver you can leverage the entire Elasticsearch DSL to implement all kinds of queries (see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-range-query.html). To go down this route, you can add your own search field to the Query type in your schema and write a custom resolver.
type Query {
searchNotesByCreatedAt(start: String!, end: String!): NotesConnection
}
Then via the console or via your own CloudFormation stack you can write a resolver like this:
{
"version": "2017-02-28",
"operation": "GET",
"path": "/note-<your-api-id>/doc/_search", // created by amplify
"params": {
"body": {
"sort": [{ "createdAt" : {"order" : "desc"}}],
"query": {
"range" : {
"createdAt" : {
"gte": $ctx.args.start,
"lte": $ctx.args.end
}
}
}
}
}
}
You will only need to deploy this resolver using the console or your own CF stack temporarily. Work is being done to allow you to write your own resolvers from within the amplify CLI. For more information on how this will work see https://github.com/aws-amplify/amplify-cli/issues/574.
Let me know if this works for you.

Related

How to graphql after a certain date in contentful?

I'm using Contentful's GraphQL API. What I want to do is to query all the events that haven't past yet.
I tried using lt, but that doesn't seem to be working. I also found out that the date is a string, so what options do I have?
eventCollection(where: {eventEndDate: {lt: "2022-10-27T00:00:00.000-06:00"}}){
items {
slug
eventEndDate
}
}
A normal query (without the where condition) gives you:
"eventCollection": {
"items": [
{
"slug": "black-friday",
"eventEndDate": "2022-11-27T12:00:00.000-07:00"
}
]
}
You should have an eventEndDate_gte filter available. On every field, there will be type dependent filter available. It's best to use GraphiQL or the GraphQL Playground to discover available filter options.
The following filter works fine for my space.
query {
tilPostCollection(where: {date_gte: "2022-09-05T00:00:00.000+02:00"}) {
items {
title
date
}
}
}

grpc/protobuffer ask for specific fields

GraphQL lets you ask for specific fields, the response contains only the fields that you had asked for. For example:
a graphql query like:
{
hero {
name
}
}
will return:
{
"data": {
"hero": {
"name": "R2-D2"
}
}
}
where as a graphQl query like:
{
hero {
name
friends {
name
}
}
}
would return:
{
"data": {
"hero": {
"name": "R2-D2",
"friends": [
{
"name": "Luke"
},
{
"name": "Han Solo"
},
{
"name": "Leia"
}
]
}
}
}
Is there a similar mechanism/library/pattern that can be used in gRPC to achieve the same?
FieldMask is similar in protobuf. It is a list of fields to retain, so the first example would be paths: "hero.name" and the second would be paths: ["hero.name", "hero.friends.name"].
It is probably most frequently used to specify which fields should be changed in an update. But it can equally be used to specify the fields that should be returned.
The server can either process the FieldMask directly (e.g., only using the listed fields in a SELECT SQL query), or it can retrieve all the information and filter the result using FieldMaskUtil.merge() to copy just the requested fields into a new proto message to return to the client.

GraphQL: Explore API without a wildcard (*)?

I am new to GraphQL and I wonder how I can explore an API without a possible wildcard (*) (https://github.com/graphql/graphql-spec/issues/127).
I am currently setting up a headless Craft CMS with GraphQL and I don't really know how my data is nested.
Event with the REST API I have no chance of just getting all the data, because I have to setup all the endpoints and therefore I have to know all field names as well.
So how could I easily explore my CraftCMS data structure?
Thanks for any hints on this.
Cheers
merc
------ Edit -------
If I use #simonpedro s suggestion:
{
__schema {
types {
name
kind
fields {
name
}
}
}
}
I can see a lot of types (?)/fields (?)...
For example I see:
{
"name": "FlexibleContentTeaser",
"kind": "OBJECT",
"fields": [
{
"name": "id"
},
{
"name": "enabled"
},
{
"name": "teaserTitle"
},
{
"name": "text"
},
{
"name": "teaserLink"
},
{
"name": "teaserLinkConnection"
}
]
But now I would like to know how a teaserLink ist structured.
I somehow found out that the teaserLink (it is a field with the type Entries, where I can link to another page) has the properties url & title.
But how would I set up query to explore the properties available within teaserLink?
I tried all sorts of queries, but I am always confrontend with messages like this:
I would be really glad if somebody could give me another pointer how I can find out which properties I can actually query...
Thank you
As far as I'm concerned currently there is no graphql implementation with that capability. However, if what you want to do is to explore the "data structure", i.e, the schema, you should use schema instrospection, which was thought for that (explore the graphql schema). For example, a simple graphql instrospection query would be like this:
{
__schema {
types {
name
kind
fields {
name
}
}
}
}
References:
- https://graphql.org/learn/introspection/
UPDATE for edit:
What you want to do I think is the following:
Make a query like this
{
__schema {
types {
name
kind
fields {
name
type {
fields {
name
}
}
}
}
}
}
And then find the wished type field to grab more information (the fields) from it. Something like this (I don't know if this works, just an idea):
const typeFlexibleContentTeaser = data.__schema.types.find(t => t === "FlexibleContentTeaser")
const teaserLinkField = typeFlexibleContentTeaser.fields.find(f => f.name === "teaserLink")
const teaserLinkField = teaserLinkField.type.fields;
i.e, you have to transverse recursively through the type field.

How to get unseen, nearby documents from a Amplify - AppSync - ElasticSearch - DynamoDB Stack?

Problem:
Use Amplify.js from AWS.
A Tinder similar app.
Here you can find jobs close by.
These may only be seen once.
We should save what the user likes and dislikes.
What I've already managed:
I have the scheme:
type Query {
nearbyJobs(location: LocationInput!, km: Int): ModelJobConnection
}
type User #model {
id: ID!
name: String
interacts: [Jobinteract] #connection(name: "interactsuser")
createdAt: String
updatedAt: String
}
type Job #model #searchable {
id: ID!
name: String
location: Location
is_swiped_by: AWSJSON
interacts: [Jobinteract] #connection(name: "interactjob")
createdAt: String
updatedAt: String
}
With #searchable I have established the connection to ElasticSearch. Since this seems to be the only way to search for jobs nearby.
Now it becomes tricky.
At the moment I save in the field: is_seen_from_user all users id´s who have already seen this job. Since there were about 1000 users so far, that was ok.
This was my es query:
"body": {
"size": 30,
"sort": [
{
"createdAt": {
"order": "desc"
}
}
],
"query": {
"bool": {
"must": [
{
"range": {
"createdAt": {
"gte": "now-30d/d"
}
}
}
],
"must_not": {
"match_phrase": {
"is_swiped_by.user": "$ctx.identity.sub"
}
},
"filter": {
"geo_distance": {
"distance" : "${distance}km",
"location" : $util.toJson($ctx.args.location)
}
}
}
}
is_swiped_by.user
So I looked into the array to see if the user was there.
if yes - skip.
But now I rather have the problem that there can be more users.
This means, I can't save it into a field anymore.
There would probably have to be a new table.
type Jobinteract #model {
id: ID!
user: User! #connection(name: "interactsuser")
job: Job! #connection(name: "interactjob")
decision: Int
createdAt: String
updatedAt: String
}
The question now is. If I have the table (Jobinteract) now. Should I make it #searchable too?
Then I also have the data in ElasticSearch. But how can I bring them together?
It is then data from different indexes.
I read hasChild in ES. But don't understand exactly how this should work, if it's the right way?!
i'm also currently testing whether i can get access to ES via a lambda, so i'd just call up all the jobs nearby and compare them myself.
But that's probably not the best option.
Get 100 jobs from nearby from Elasticsearch, compare it to the table below. If there are 50 left, send them to the frontend, if not, get 100 again.
The more the user liked, the longer this call would go.
The #searchable directive does not currently support custom ElasticSearch mappings out of the box so you will need to perform some custom setup for your ElasticSearch cluster. You should be able to use joining queries such as hasChild to find all locations where there is no associated child record in the same index that indicates the user has interacted with the job before.
As of writing, the #searchable directive stores different #models in separate indexes so you will need to write a custom resolver that puts the "Interaction" child record in the same index that specifies when a user has interacted with a job and then you will need to update the ES index mapping such that it uses a join data type so you can use the hasChild query. See https://www.elastic.co/guide/en/elasticsearch/reference/current/parent-join.html for more information.

Order by nested object in RethinkDB using Go driver

How is it possible using Go driver fetch data from RethinkDB in order by of nested object?
So let's imagine I have such json in my table:
[
{
"id": "1",
"date": "2001-01-15",
"time": {
"begin": "09:00",
"end": "10:30"
}
},
{
"id": "2",
"date": "2001-01-16",
"time": {
"begin": "08:30",
"end": "10:30"
}
}
]
Go model is:
type MyTime struct {
Begin time.Time `json:"begin"`
End time.Time `json:"end"`
}
type Something struct {
Id string `json:"id"`
Date time.Time `json:"date"`
Time MyTime `json:"time"`
}
Example how it is possible to order by id:
var result []Something
db.Table("someTable").OrderBy("id").Run(session).All(&result)
I tried to order by beginning of time like this (thinking that the approach is the same as in ArangoDB, but apparently it is not):
var result []Something
db.Table("someTable").OrderBy("time.begin").Run(session).All(&result)
I saw an example on the official site how it works by using native javascript driver
Example: Use nested field syntax to sort on fields from subdocuments. (You can also
create indexes on nested fields using this syntax with indexCreate.)
r.table('user').orderBy(r.row('group')('id')).run(conn, callback)
But it is not really clear how to transform it to Go.
Any idea how to make it work?
You can use a function, something like this:
db.Table("someTable").OrderBy(func(row Term) Term {
return row.Field("time").Field("begin")
}).Run(session).All(&result)

Resources