AWS AppSync GraphQL query a record by a field value - amazon-dynamodb

I have an user table, which consists of email, phone etc., and I would like to query a record based on its email or phone value (instead of #Id). Having not-adequate knowledge to do this - I wrote a schema like this:
type Query {
...
getUser(id: ID!): User
getUserByEmail(input: GetUserByEmailInput!): User
...
}
input GetUserByEmailInput {
email: String!
}
In resolver against getUserByEmail(..), I tried to experiment but nothing worked so far, so its remain to default state:
So when I ran a query like this to the Queries console:
query GetUserByEmail {
getUserByEmail(input: {email: "email#email.com"}) {
id
name
email
image
}
}
this returns an error like this:
{
"data": {
"getUserByEmail": null
},
"errors": [
{
"path": [
"getUserByEmail"
],
"data": null,
"errorType": "DynamoDB:AmazonDynamoDBException",
"errorInfo": null,
"locations": [
{
"line": 41,
"column": 5,
"sourceName": null
}
],
"message": "The provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: xxx)"
}
]
}
How can I query a record by non-Id field value?

If you use the Create Resources flow in the console, it will create a listUsers query that looks like the following for example. Note that the DynamoDb operation will be a Scan that has a DynamoDb filter expression where you can use any field to query DynamoDb. See below for the mapping template.
{
"version": "2017-02-28",
"operation": "Scan",
"filter": #if($context.args.filter) $util.transform.toDynamoDBFilterExpression($ctx.args.filter) #else null #end,
"limit": $util.defaultIfNull($ctx.args.limit, 20),
"nextToken": $util.toJson($util.defaultIfNullOrEmpty($ctx.args.nextToken, null)),
}
You can find more details about Scans and filter expressions in the AWS AppSync documentation:
https://docs.aws.amazon.com/appsync/latest/devguide/tutorial-dynamodb-resolvers.html

Related

Scan in array of Nested Objects - DynamoDB

So, i am trying to filter objects inside of an array using dynamo db.
This is my sample object
client: {
"name":"etc"
"subscriptions": [
{
"status": "canceled"
... other fields
},
{
"status": "active"
... other fields
}
]
}
I am using filter expressions and dynamoose scan method, what i want to achieve in this case would be the scan bring me back all subscriptions that have the canceled status, is this possible using dynamodb and this kind of objects?.
var filter = {
FilterExpression: "#subscriptions.#status = :statusValue",
ExpressionAttributeNames: {
"#subscriptions":"subscriptions",
"#status": "status"
},
ExpressionAttributeValues:{
":statusValue": "canceled"
}
};
dynamooseEntity.scan(filter).exec();

Facing issue while trying to run the updateitem in dynamo db

I am able to fetch the record from dynamo db and view the response successfully. I need to modify the fetched 'ACCOUNTNAME' attribute in the 'items' array and update the json and also update in dynamo db. Now when I try to update the fetched records I end up with the Invalid attribute value type exception.
I was trying to update it using the key with Array of Strings which is provided with code snippet also tried to update inside for loop using the individual string but both failed with same exception as
"statusCode": 400,
"body": {
"message": "Invalid attribute value type",
"error": {
"errorMessage": "ValidationException"
}
}
I tried to create params and update the call inside the for loop by setting the key as below,
Key: {
"UUID": {
"S": usersOfAccountFromDB.body.Items[key].UUID
}
,
"TYPE": {
"S": user
}
}
but also failed with the same exception.
Fetched Json from dynamo db
[
{
"DEFINITION": "914ba44a-8c26-4b60-af0f-96b6aa37efe6",
"UUID": "830a49cb-4ed3-41ae-b111-56714a71ab98",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
{
"DEFINITION": "1f60fded-323d-40e1-a7f8-e2d053b0bed0",
"UUID": "47db3bbe-53ac-4e58-a378-f42331141997",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
{
"DEFINITION": "05ddccba-2b6d-46bd-9db4-7b897ebe16ca",
"UUID": "e7290457-db77-48fc-bd1a-7056bfce8fab",
"TYPE": "USER",
"RELATION": "01efd131-6a5d-4068-889e-9dba44262da5",
"ACCOUNTNAME": "Wolff LLC"
},
.
.
.
.]
Now I tried to iterate the Json and setup UUID which is the key as the String array as below,
var userUUIDArray : string[] = [];
for (let key in usersOfAccountFromDB.body.Items) {
userUUIDArray.push(usersOfAccountFromDB.body.Items[key].UUID);
}
for (var uuid of userUUIDArray) {
console.log("UUID : " +uuid); // prints all the uuid
}
// Creating a parameter for the update dynamo db
var params = {
TableName: <tableName>,
Key: {
"UUID": {
"SS": userUUIDArray
}
,
"TYPE": {
"S": user
}
},
UpdateExpression: 'SET #ACCOUNTNAME = :val1',
ExpressionAttributeNames: {
'#ACCOUNTNAME': 'ACCOUNTNAME' //COLUMN NAME
},
ExpressionAttributeValues: {
':val1': newAccountName
},
ReturnValues: 'UPDATED_NEW',
};
//call the update of dynamodb
const result = await this.getDocClient().update(param).promise();
I get the error as below,
"body": {
"message": "Invalid attribute value type",
"error": {
"errorMessage": "ValidationException"
}
}
All the approaches failed with same above exception
The update operation which your code currently uses only allow a single item to be updated.
IIUC, you want to update multiple items with one API call. For this you need to use batchWrite operation. Keep in mind that you cannot update more than 25 items per invocation.
The origin of the error you are getting
Your code fails due to the use of "SS" in the UUID field. This field is of type string so you must use "S". Note however that since you're using the document client API you do not need to pass values using this notation. See this answer for further details.
I have resolved the issue now by running the update statement one by one using loop
for (let key in usersOfAccountFromDB.body.Items) {
var updateParam = {
TableName: process.env.AWS_DYNAMO_TABLE,
Key: {
UUID: usersOfAccountFromDB.body.Items[key].UUID,
TYPE: user
},
UpdateExpression: "SET #ACCOUNTNAME = :val1",
ExpressionAttributeNames: {
'#ACCOUNTNAME': 'ACCOUNTNAME'
},
ExpressionAttributeValues: {
":val1": newAccountName
},
ReturnValues: "UPDATED_NEW",
};
const result = await this.getDocClient().update(updateParam).promise();
}

AppSync client query not returning complete data response

I am having an issue getting results back from my AppSync API via AWSAppSyncClient. I can run the query in the AWS AppSync console and get the complete results, however when I run the query from my client the portion of the results I am looking for returns an empty array.
I have tried slimming down the query to return less results, as I read at one point that dynamo will run a filter on the results being returned if you do not provide your own. I have also read this could have something to do with the partition keys used in the dynamoDB table, however AppSync provisioned that resource for me and handled the initial config. I am new to working with AppSync so I am sort of drawing a blank on where to even start looking for the issue because there is not even an error message.
The Query I am running
export const getUserConversations = `query getUser($id: ID!) {
getUser(id: $id) {
id
conversations {
items {
conversation{
id
associated{
items{
convoLinkUserId
}
}
}
}
}
}
}
`;
Call being made in a redux actions file
export const getUserConvos = (id) => async dispatch => {
AppSyncClient.query({
query: gql(getUserConversations),
variables: {
id: id
}
}).then(res => {
console.log("RES FROM CONVO QUERY", res)
})
}
This is the response I am getting in the browser
Notice conversations.items returns an empty array.
getUser:
conversations:
items: []
__typename: "ModelConvoLinkConnection"
__proto__: Object
id: "HIDDEN_ID"
__typename: "User"
__proto__: Object
__proto__: Object
However if i run the exact same query in the playground on the AppSync console I get this...
{
"data": {
"getUser": {
"id": "HIDDEN_ID",
"conversations": {
"items": [
{
"conversation": {
"id": "HIDDEN_ID",
"associated": {
"items": [
{
"convoLinkUserId": "HIDDEN_ID"
},
{
"convoLinkUserId": "HIDDEN_ID"
}
]
}
}
},
{
"conversation": {
"id": "HIDDEN_ID",
"associated": {
"items": [
{
"convoLinkUserId": "HIDDEN_ID"
},
{
"convoLinkUserId": "HIDDEN_ID"
}
]
}
}
}
]
}
}
}
}
*HIDDEN_ID is a placeholder
I know that the objects are in my DB, however if i run the query via my react application I get nothing, and if I run it in the console on AWS I get another. I need to be able to have access to these conversations via the client. What could be causing this?

AppSync Optional Resolver

Using AWS AppSync, Graphql and DynamoDB
The following query is causing me an issue.
eventId is an optional field.
When running the below query, records with the optional eventId field trigger an error. I would expect eventId to be null, if the resolver could not execute.. However the below message is triggered.
How would this be resolved?
query listTickets {
listTickets {
items {
id,
eventId {
id,
}
}
}
}
"message": "The provided key element does not match the schema (Service: AmazonDynamoDBv2; Status Code: 400; Error Code: ValidationException; Request ID: FTFDINCA42EALGI59I2VGH07G7VV4KQNSO5AEMVJF66Q9ASUAAJG)"
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"id": $util.dynamodb.toDynamoDBJson($ctx.args.eventId),
}
}

Why does my ConditionExpression in PutItem not work?

I'm trying to perform a PutItem action against dynamoDB table with itemID as Primary partition key and createdAt as Primary sort key, with a condition like follows:
{
"TableName": "ShoppingBasket",
"Item": {
"itemID": {
"N": "7456473"
},
"createdAt": {
"S": "2001-02-03T04:05:06Z"
}
},
"ConditionExpression": "contains(createdAt, :created_at)",
"ExpressionAttributeValues": {
":created_at": {"S": "Z"}
}
}
The expression is there to ensure that ISO8601 UTC time is provided for the createdAt attribute. However it gives me: ConditionalCheckFailedException: The conditional request failed
What am I doing wrong?
Using contains on items that do not exist yet will always evaluate to false. Instead, please perform input validation on the client side before calling PutItem, checking that createdAt is of the correct form.

Resources