AWS Amplify GraphQL Query with Computed Field - aws-amplify

I am looking to implement a query named driversByActiveStatus that returns only the active, inactive, or all drivers respectively for the following Driver type,
type Driver
#model
#auth(rules: [
{allow: private}
])
#key(name: "byLastName", fields: ["lastName", "id"], queryField: "driversByLastName")
#key(name: "byActiveStatus", fields: ["active", "id"], queryField: "driversByActiveStatus") {
id: ID!
firstName: String!
lastName: String!
# computed field that is calculated based on startDate and endDate
# true if startDate < currentDate < endDate
# false if currentDate < startDate || current > endDate
active: Boolean
startDate: AWSDateTime!
endDate: AWSDateTime!
}
The query driversByActiveStatus should work as follows,
it returns all the drivers if the active parameter is null
it returns only the active drivers if the active parameter is true (an active driver is a DynamoDB record where the current date is between its startDate and endDate, i.e., startDate < currentDate < endDate)
it returns only the inactive drivers if the active parameter is false
What would be the best way to achieve this in AWS Amplify?
From what I read on https://docs.amplify.aws/cli/ it looks like it may be possible to implement the query by overwriting the auto-generated VTL resolvers Query.driversByActiveStatus.req.vtl and Query.driversByActiveStatus.res.vtl, and replacing the active field value with a calculated value based on startDate and endDate in the returned result set in the result mapping resolver.
Has anyone implemented something similar? If so can you please shed some lights or share the code snippet as there is only limited documentation on AppSync VTL resolvers.

Related

Dynamoose model update with hash key

I'm trying to execute an update against a dynamoose model. Here's the docs on calling model.update
Model.update(key[, updateObj[, settings]],[ callback])
key can be a string representing the hashKey or an object containing the hashKey & rangeKey.
My schema has both a hash key (partition key) and range key (sort key) like this:
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
},
date: {
type: Date,
rangeKey: true,
},
status: String,
});
I've created an object like this (with a fixed timestamp for demoing)
let timestamp = 1606781220842; // Date.Now()
model.create({
id: "1",
date: new Date(timestamp),
status: "pending",
});
I'd like to be able to update the status property by referencing just the id property like this:
model.update({id: "1"}, {status: "completed"})
// err: The provided key element does not match the schema
model.update("1", {status: "completed"})
// err: Argument of type 'string' is not assignable to parameter of type 'ObjectType'
But both result in the shown errors:
I can pass in the full composite key if I know the timestamp, so the following will work:
let timestamp = 1606781220842; // Date.Now()
model.update({ id: "1", date: timestamp }, { status: "completed" });
However, that requires me holding onto the timestamp and persisting alongside the id.
The ID field, in my case, should, by itself, be unique, so I don't need both to create a key, but wanted to add the date as a range key so it was sortable. Should I just update my schema so there's only a single hash key? I was thinking the docs that said a "`key can be a string representing the hashkey" would let me just pass in the ID, but that throws an error on compile (in typescript).
Any suggestions?
The solution here is to remove the rangeKey from the date property.
This is because in DynamoDB every document/item must have a unique “key”. This can either be the hashKey or hashKey + rangeKey.
Since you mention that your id property is unique, you probably want to use just the hashKey as the key, which should fix the issue.
In your example there could have been many documents with that id, so DynamoDB wouldn’t know which to update.
Don’t forget that this causes changes to your table so you might have to delete and recreate the table. But that should fix the problem you are running into.
Logically there is nothing stopping you than inserting more than 1 entry into the same partition (in your case the unique id). You could insert more than one item with the same id, if it had a different date.
Therefore if you want to get an item by only its partition key, which is really a unique ID, you need to use a query to retrieve the item (as opposed to a GET), but the return signature will be a collection of items. As you know you only have one item in the partition, you can take the first item, and specify a limit of 1 to save RCU.
// create model
let model = dynamoose.model(
"SampleStatus",
{
id: {
type: String,
hashKey: true,
"index": {
"name": "index_name",
"rangeKey": "date",
}
},
date: {
type: Date
},
status: String,
});
You have to tell the schema that hashKey and range are one partition key.
Ref: https://dynamoosejs.com/guide/Schema#index-boolean--object--array

Amplify Graphql not respecting the limit on my query

I have an Amplify application, using a DynamoDB table with ~50 items and accessing it via a React app.
The initial (simplified) model:
type Video #model
#key(name: "ByOrganization", fields: ["videoOrganizationId", "id"], queryField: "videosByOrganization")
{
id: ID!
createdAt: AWSDateTime
title: String!
season: Int
episode: Int
owner: String
editor: String
organization: Organization #connection
videoOrganizationId: ID
}
on the code I call this query on an Apollo React component:
<Query
query={query}
variables={{
{
limit: 100,
},
}}
pollInterval={5000}
>
{children}
</Query>);
The limit of 100 items should be enough to bring all items from the database, however, it is not what happens, and it limit it to a number of items (~20-30 items)
I have tried adding different indexes to the table:
#key(name: "ByOrganizationSortedByCreated", fields: ["videoOrganizationId", "createdAt"], queryField: "videosByOrganizationSortedByCreated")
#key(name: "ByOrganizationSortedByTitle", fields: ["videoOrganizationId", "title"], queryField: "videosByOrganizationSortedByTitle")
#key(name: "ByOrganizationSortedByTitleSeasonEpisode", fields: ["videoOrganizationId", "title", "season", "episode"], queryField: "videosByOrganizationSortedByTitleSeasonEpisode")
None of them have worked
Some items that clearly should be returned on my query are left behind
I also was trying to find any reference about limitatinos on DynamoDb number of returned items, or some odd behaviour that I'm not aware of... no success
There is also some super weird behaviours
ie: if I just add a sortDirection: 'DESC', it returns less results!
Does anyone has any idea why is this happening?

Querying DynamoDB with partition key and secondary index in Javascript

Having the following table definition in DynamoDB
pk: userId (string)
sk: carId (string)
index: carModelIndex (string)
If I would like to query all the cars rented by a given user for a given model. How I would go about that?.
Please note I am using the javascript sdk for dynamodb.

How to write a Spring JPA repository method name to activate the Distinct clause in Couchbase?

Working on a Java application that uses Spring Data Couchbase 2.2.0.RELEASE...
Starting with a list of JSON objects that represent Book objects:
[
{id: 123, title: "Abc", category: "A"},
{id: 456, title: "Efg", category: "B"},
{id: 789, title: "Abc", category: "A"}
]
The array of Book objects are inserted into Couchbase. Later, the application would like get a list of distinct book titles back based on a category filter. Following some of the Spring documentation, I've arrived at this method name in the BookRepository interface:
List<Book> findDistinctTitleByCategory(String category);
However, the query that is created by Spring does not contain the Distinct clause for title. Here's is the final query that Spring sends to the CB cluster where bucket name here is default:
Executing N1QL query: {"statement":"SELECT META(`default`).id AS _ID, META(`default`).cas AS _CAS, `default`.* FROM `default` WHERE (`category` = \"A\")","scan_consistency":"not_bounded"}
Am I writing the method name wrong?
SDC currently does not support query derivation for distinct. I have created a ticket for enhancement here. In the meantime, you can work around by directly using #Query instead of n1ql.selectEntity, provide the select part.
If you are fetching only the title, SDC supports projections.
interface OnlyTitle {
String getTitle();
}
#Query(...)
OnlyTitle findDistinctTitleByCategory(String category);

Nullable embedded value object with not nullable fields

I created an entity "Person" in Doctrine2, and I added to it an Adress entity, which is a value object (embeddable).
I want to allow a Person creation, without an Address, so I tag my embedded as "nullable = true". But on the other hand, my Address entity, if it exists, SHOULD contains at least some information (like city, zip code, etc...). So it has "nullable = false" attributes.
Address:
type: embeddable
fields:
[...]
city:
type: string
length: 255
nullable: false
Person:
type: entity
table: null
embedded:
address:
class: Address
nullable: true
It seems that the "nullable = true" of the embedded object was not working.
Do you know if it's a normal Doctrine behaviour ?
Do I have to put all my embeddable attributes to nullable = true ?

Resources