Update-ing dynamodb item using Appsync - amazon-web-services

In AppSync i want to update item with array or stringset like this:
mutation addmeta{
addMetaDataOnPhoto(id:"xyz", metadata:["word1", "word2",...]){
metadata
}
}
this is how my mutation type looks:
type Mutatation{
addMetaDataOnPhoto(id: String!, metadata: [String]!): Photo
}
My question is how should look resolver for this mutation.
Thanks! :)

In order to update an attribute without replacing the entire item, you should use the UpdateItem DynamoDB operation.
In your example, if you want to replace the metadata array, your request mapping template shoud look like below:
{
"version" : "2017-02-28",
"operation" : "UpdateItem",
"key" : {
"id" : { "S" : "${context.arguments.id}" }
},
"update" : {
"expression" : "SET metadata = :vals",
"expressionValues": {
":vals" : $util.dynamodb.toDynamoDBJson($ctx.args.metadata)
}
}
}
Note: $util.dynamodb.toDynamoDBJson will convert your array into a DynamoDB typedValue. For more information and utilities see the AWS AppSync util reference.

Related

Get parent object in child resolver AWS AppSync

I have a graphQL schema like this:
type Post {
id: String!
title: String!
content: String!
user: User!
}
type Query {
allPosts: [Post!]
singlePost(id: String!): Post!
}
type User {
name: String!
posts: [Post!]
}
The dynamo DataSource handles queries. In the query below, the user will be handled with a different resolver because it depends on different GSI.
query MyQuery {
allPosts {
content
title
user{
name
}
}
}
allPosts resolver looks like this:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "#t = :sk",
"expressionNames" : {
"#t": "type"
},
"expressionValues" : {
":sk": $util.dynamodb.toDynamoDBJson("post")
}
},
"index" : "GSI",
"select" : "ALL_ATTRIBUTES"
}
The resolver for user in the Post type is:
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "PK = :pk AND SK = :sk",
"expressionValues" : {
":pk": "NEED TO ACCESS THE Partition KEY FROM ALL_POSTS",
":sk": $util.dynamodb.toDynamoDBJson("profile")
}
},
"select" : "ALL_ATTRIBUTES"
}
I need to access the partition key from the post object in each iteration to fetch the user of a specific id, just like the author resolver in this code (https://github.com/benawad/graphql-n-plus-one-example/blob/master/src/index.js):
const resolvers = {
Book: {
author: async parent => {
const author = await knex("users")
.select()
.where("id", parent.authorId)
.first();
return author;
}
},
Query: {
books: async () => {
const books = await knex("books")
.select()
.limit(10);
return books;
}
}
};
I've found the answer finally, the required object is stored in $ctx.source. All I had to do is to change the user resolver to this (Provided the result object have PK inside it):
{
"version" : "2017-02-28",
"operation" : "Query",
"query" : {
"expression" : "PK = :pk AND SK = :sk",
"expressionValues" : {
":pk": $util.dynamodb.toDynamoDBJson($ctx.source.PK),
":sk": $util.dynamodb.toDynamoDBJson("profile")
}
},
"select" : "ALL_ATTRIBUTES"
}
The $context.source references the parent object of the current field that’s being resolved. In this example, $ctx.source.PK refers to the individual Post object, which is then used for the query expression. ($context and $ctx are same). It works exactly like the parent argument in the apollo-server framework.

Appsync GraphQL with "None" data source trying to pass through a list of return items

I have an AppSync API that I'm using for an app. One action I'm trying to do is have a Lambda function that collects certain data fire off a GraphQL mutation, and then have a subscription on my front end collect that data when the mutation is called. This data is ephemeral and I don't want to write it to a database, so I'm trying to set up a "None" data source in AppSync just to pass this data off.
I have an AppSync GraphQL API set up with the following (simplified) schema:
type Mutation #aws_api_key
#aws_cognito_user_pools {
sendSearchResults(input: SearchResultInputHeader!): SearchResultOutputHeader
}
input SearchResultInput {
assetId: String
score: Float
}
input SearchResultInputHeader {
callId: String
results: [SearchResultInput]
}
type SearchResultOutput #aws_api_key
#aws_cognito_user_pools {
assetId: String
score: Float
}
type SearchResultOutputHeader #aws_api_key
#aws_cognito_user_pools {
callId: String
results: [SearchResultOutput]
}
and the following request / response resolver mappings:
// REQUEST::
{
"version": "2017-02-28",
"payload": {
"callId": "${context.arguments.input.callId}",
"results": "${context.arguments.input.results}"
}
}
// RESPONSE::
$util.toJson($context.result)
I am able to pass the callId String through this mutation but I am unable to get the results to pass through
// INPUT::
mutation MyMutation {
sendSearchResults(input: {resultsIn: [{assetId: "0001", score: 10}, {assetId: "0002", score: 22}], callId: "aaa-aaa-aaa"}) {
callId
resultsOut {
assetId
}
}
}
// RETURN::
{
"data": {
"sendSearchResults": {
"callId": "aaa-aaa-aaa",
"resultsOut": null
}
}
}
So I have two main questions:
How can I get the resolver/mutation to return a list of results rather than null?
Any other suggestions on passing data through an AppSync mutation and subscription? Or does this approach seem to make sense without writing to a database and just receiving a key?
Thanks!
// REQUEST::
{
"version": "2017-02-28",
"payload": {
"callId": "${context.arguments.input.callId}",
"results": "${context.arguments.input.results}"
}
}
// INPUT::
mutation MyMutation {
sendSearchResults(input: {resultsIn: [{assetId: "0001", score: 10}, {assetId: "0002", score: 22}], callId: "aaa-aaa-aaa"}) {
callId
resultsOut {
assetId
}
}
}
Here is results and resultsIn are different is two places.

Dynamodb - scan map attribute with GraphQL

I'm using GraphQL to scan a collection in dynamodb that looks like this:
{
"config_name": "COLOR_PALETTE",
"config_value": {
"SHOW_CUSTOM_SUBSCRIPTION": "NO",
"SHOW_DD_SUBSCRIPTION": "NO",
"SHOW_GRADIENT_SUBSCRIPTION": "YES",
"SHOW_SOLID_SUBSCRIPTION": "NO"
}
}
I want to return "config_value" as key value pair. How I define AppSync schema and resolver to get "config_value" as key value pair ?
If you set your schema up as follows:
type ConfigValues {
SHOW_CUSTOM_SUBSCRIPTION: String!
SHOW_DD_SUBSCRIPTION: String!
SHOW_GRADIENT_SUBSCRIPTION: String!
SHOW_SOLID_SUBSCRIPTION: String!
}
type Query {
getConfigValues(configName: String!): ConfigValues
}
schema {
query: Query
}
With a resolver on getConfigValues with a request mapping template of:
{
"version": "2017-02-28",
"operation": "GetItem",
"key": {
"config_name": $util.dynamodb.toDynamoDBJson($ctx.args.configName),
}
}
And a response mapping template of:
$util.toJson($ctx.result.config_value)
Performing the following query:
query {
getConfigValues(configName: "COLOR_PALETTE") {
SHOW_CUSTOM_SUBSCRIPTION
SHOW_DD_SUBSCRIPTION
SHOW_GRADIENT_SUBSCRIPTION
SHOW_SOLID_SUBSCRIPTION
}
}
Will have the response of:
{
"data": {
"getConfigValues": {
"SHOW_CUSTOM_SUBSCRIPTION": "NO",
"SHOW_DD_SUBSCRIPTION": "NO",
"SHOW_GRADIENT_SUBSCRIPTION": "YES",
"SHOW_SOLID_SUBSCRIPTION": "NO"
}
}
}
This answer assumes that your Primary partition key of your DynamoDB table is set to be config_name.

AppSync query on Global Secondary Index

I'm trying to get a record from a GSI and I'm stucked.
API Schema:
type DriverInfos {
id: String!
status: Int
lastLat: Float
lastLng: Float
idDriver: String # GSI
}
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfos
}
Resolver :
{
"version" : "2017-02-28",
"operation" : "Query",
"index" : "idDriver-index",
"query" : {
## Provide a query expression. **
"expression": "#idDriver = :idDriver",
"expressionNames" : {
"#idDriver" : "idDriver"
},
"expressionValues" : {
":idDriver" : {
"S" : "${ctx.args.idDriver}"
}
}
}
}
Query :
query getDriverInfosByDriver{
getDriverInfosByDriver(idDriver: "1")
{
idDriver
status
lastLat
lastLng
}
}
Return :
{
"data": {
"getDriverInfosByDriver": {
"idDriver": null,
"status": null,
"lastLat": null,
"lastLng": null
}
}
}
GSI is well activated : Name : "idDriver-index" - PartitionKey : idDriver (String)
Try with other ids : 2, 3, ...
It seems that it comes from the resolver. I tried with different resolver but it always return an error.
Thank you in advance for your answers.
The issue is that a Query operation always returns a set of results not just one. If you want to leave your query type like this:
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfos
}
then you should to change your response mapping template to this:
#if($ctx.result.items.size() > 0)
$util.toJson($ctx.result.items[0])
#else
null
#end
If instead the getDriverInfosByDriver query should return multiple info objects then you should change your schema to:
type DriverInfo {
id: String!
status: Int
lastLat: Float
lastLng: Float
idDriver: String # GSI
}
type DriverInfoConnection {
items: [DriverInfo]
nextToken:String
}
type Query {
getDriverInfosByDriver(idDriver: String): DriverInfoConnection
}
You can then leave your response mapping template as the default:
$util.toJson($ctx.result)
and then query it like so
query getDriverInfosByDriver{
getDriverInfosByDriver(idDriver: "1") {
items {
idDriver
status
lastLat
lastLng
}
}
}

CouchDB link multiple documents

Is it possible to link multiple documents in one view.
Eg :
{
"_id" : "0b86008d8490abf0b7e4f15f0c6a463b",
"name" : "copenhagen"}
{
"_id" : "8986008d8490abf0b7e4f15f0c6a333b",
"player" : "Mark"
}
{
"_id" : "4b86008d8490abf0b7e4f15f0c6a463c",
"location" : { "uuid" : "0b86008d8490abf0b7e4f15f0c6a463b"},
"player" : { "uuid" : "8986008d8490abf0b7e4f15f0c6a333b"},
"session" : "9876"
}
I want a view to include location document as well as the player document.
View :
"fetchByLocationAndPlayer": {
"map": "function(doc) { if (doc.session) { emit(doc.session, { _id : **doc.location.uuid** }); } }"
}
In the query I use includedocs = true.
How do I emit multiple documents corresponding to multiple keys in one document?
Yes it is possible. Just use two emits instead of one
emit(doc.session, {_id:doc.location.uuid});
emit(doc.session,{_id:doc.player.uuid});
Couch db wiki lists yet another way of doing this by iterating over the array and emitting linked docs one by one.