#✅ - Batch Delete and Need for More and Better Examples of Custom Queries and Mutations

20 messages · Page 1 of 1 (latest)

ocean mica
#

First question, how can I do a batch delete of items associated via a one-to-many relationship? For example, a Product is associated with multiple Image items. When I delete a Product, I want the associated Image items deleted as well.
Second question, where can I find more documentation or at least more examples of custom queries and mutations than are here: https://docs.amplify.aws/javascript/build-a-backend/data/custom-business-logic/

knotty marsh
#

I am looking for the same

velvet laurel
ocean mica
ocean mica
# velvet laurel https://docs.amplify.aws/react/build-a-backend/data/connect-to-existing-data-sou...

I'm sure this is a naive/dumb question but with the BatchDeleteItem, for example, where would this code live?


export function request(ctx) {
  const { authorId, postId } = ctx.args;
  return {
    operation: 'BatchDeleteItem',
    tables: {
      authors: [util.dynamodb.toMapValues({ authorId })],
      posts: [util.dynamodb.toMapValues({ authorId, postId })],
    },
  };
}``` 
I guess it goes in amplify/data/batchDeleteItem.js -- or something like that.
velvet laurel
#

Yes, you can create the file at amplify/data/batchDeleteItem.js or similar.

atomic boltBOT
#

✅ - Batch Delete and Need for More and Better Examples of Custom Queries and Mutations

#

Answer selected!
https://docs.amplify.aws/react/build-a-backend/data/connect-to-existing-data-sources/connect-external-ddb-table/#batchdeleteitem
Kudos to @velvet laurel!
#1265735908066459800 message

fallow tartan
#

I don't think a selected answer is completely warranted. I'm still incredibly confused as to how I should actually use this. How are we supposed to define the schema and execute the code?

My sad attempt:

amplify/data/resource.ts
`SectionArea: a
.model({
id: a.id().required(),
editionId: a.id().required(),
title: a.string().required(),
description: a.string(),
//relationships && aws data
sections: a.hasMany('Section', ['sectionAreaId', 'editionId']),
requirements: a.hasMany('Requirement', ['sectionAreaId', 'editionId']),
sightReadings: a.hasMany('SightReading', ['sectionAreaId', 'editionId']),
createdAt: a.datetime(),
updatedAt: a.datetime(),
})
.identifier(['id', 'editionId'])
.authorization(allow => [
allow.groups(['dev', 'admin']),
allow.groups(['staff']).to(['create', 'read', 'update']),
allow.authenticated().to(['read']),
]),

batchCreateSectionAreas: a
.mutation()
.arguments({
id: a.id(),
editionId: a.id().required(),
title: a.string().required(),
description: a.string(),
})
.authorization(allow => [allow.authenticated()])
.handler(a.handler.custom({
dataSource: a.ref('SectionArea'),
entry: './batchCreateSectionAreas.js'
}))
.returns(a.ref('SectionArea').array()),`

batchCreateSectionAreas.js'
`import { util } from '@aws-appsync/utils';

export function request(ctx) {
const { id, editionId, title, description } = ctx.args;
return {
operation: 'BatchPutItem',
tables: {
SectionArea: [util.dynamodb.toMapValues({ id: id ?? util.autoId(), editionId, title, description })],
},
};
}

export function response(ctx) {
return ctx.result;
}`

#

Nor does it tell me how to execute the code.

const values = [ { editionId: '6c5fee20-6878-4c0d-9159-4eaa469b98c4', id: '61325c7c-a534-436a-bbf6-d4d9ee9a3cdc', title: 'Title 1', description: 'D1' }, { editionId: '6c5fee20-6878-4c0d-9159-4eaa469b98c4', id: '99523bcb-dcc3-40c3-a518-fdcccc6938de', title: 'Title 2', description: 'D2' }, { editionId: '6c5fee20-6878-4c0d-9159-4eaa469b98c4', id: 'd450b976-de5e-4c8e-a543-9c1251136793', title: 'Title 3', description: 'D3' } ]

const { data: bulkData, errors: bulkErrors } = await client.mutations.bulkCreateSectionAreas(values); console.log('bulk', bulkData, bulkErrors);

Error: batchCreateSectionAreas requires arguments 'editionId'

So maybe the definition in the schema is wrong.

Or am I supposed to execute more along the lines of this:

for(const item of values) { const { data: bulkData, errors: bulkErrors } = await client.mutations.bulkCreateSectionAreas({ editionId: '6c5fee20-6878-4c0d-9159-4eaa469b98c4', id: item.id, title: item.title, description: item.description }); console.log('bulk', bulkData, bulkErrors); }

but that also produces an error:
Can't resolve value (/batchCreateSectionAreas ) : type mismatch error, expected type LIST

fallow tartan
#

I also wanted to mention that I tried setting the arguments as an array of refs, however it won't deploy like that, as array doesn't meet the requirement.

batchCreateSectionAreas: a .mutation() .arguments({ items: a.ref('SectionArea').array() }) .authorization(allow => [allow.authenticated()]) .handler(a.handler.custom({ dataSource: a.ref('SectionArea'), entry: './batchCreateSectionAreas.js' })) .returns(a.ref('SectionArea').array()),

TS2322: Type
RefType<SetTypeSubArg<SetTypeSubArg<RefTypeArgFactory<'SectionArea'>, 'array', true>, 'arrayRequired', true>, 'required' | 'array', undefined>
is not assignable to type BaseModelField | EnumType<readonly string[]>
Property array is missing in type
RefType<SetTypeSubArg<SetTypeSubArg<RefTypeArgFactory<'SectionArea'>, 'array', true>, 'arrayRequired', true>, 'required' | 'array', undefined>
but required in type BaseModelField
ModelField.d.ts(68, 5): array is declared here.

wanton furnace
#

@fallow tartan

There are 3 steps to make this happen:

  1. Define a function handler in your schema
  2. Create the function handler to batch delete
  3. Add a policy statement to your DynamoDb to allow for bulk actions (by default bulk actions are prohibited)

Here's an example of Batch writing

  1. Define function handler
 batchCreateTickets: a
      .mutation()
      .handler(
        a.handler.custom({
          entry: './batch-create-tickets.js',
          dataSource: a.ref('Ticket'),
        }),
      )
      .authorization((allow) => allow.publicApiKey())
      .returns(a.ref('Ticket').required().array()),
  1. Create function handler to batch delete

const TABLE_ID = // id of your table, you will not be able to reference it in the code so hard code it or use .env variables

export function request(ctx) {

  const tableName = TABLE_ID;

  // items you want to batch insert
  const todos = [
    // make sure to add these 3 props in addition to whatever data you want
    util.dynamodb.toMapValues({
      id: util.autoId(),
      createdAt: util.time.nowISO8601(),
      updatedAt: util.time.nowISO8601(),
    }),
  ];

  return {
    operation: 'BatchPutItem',
    tables: {
      [tableName]: todos,
    },
  };
}

export function response(ctx) {
  // return ctx;
  if (ctx.error) {
    util.error(ctx.error.message, ctx.error.type);
  }
  const tableName = ctx.env['TODO_TABLE'];
  return ctx.result.data[tableName];
}
#
  1. Add a policy statement to your DynamoDb to allow for bulk actions (by default bulk actions are prohibited). This example shows how you BulkWrite to a schema called Todo. Add more actions to the PolicyStatement to support other Bulk actions
const backend = defineBackend({
  auth,
  data,
})

const ddbTable = backend.data.resources.tables['Todo'];
const ddbDataSourceRoleArn =
  backend.data.resources.cfnResources.cfnDataSources['TodoTable']
    .serviceRoleArn;
if (ddbDataSourceRoleArn) {
  const ddbDataSourceRole = Role.fromRoleArn(
    Stack.of(backend.data),
    'DynamoDBServiceRoleArn',
    ddbDataSourceRoleArn,
  );
  ddbDataSourceRole.addToPrincipalPolicy(
    new PolicyStatement({
      actions: ['dynamodb:BatchWriteItem'],
      resources: [ddbTable.tableArn],
    }),
  );
}
#

This example implements BatchWrite not BatchDelete

#

But should push you in the right direction! I was stuck on this for a few days

fallow tartan
#

Thanks Steven. I'll give this a try. I've also been stuck for a few days, so I appreciate the help. 🙂

wanton furnace
#

@fallow tartan lmk if you can't figure it out

fallow tartan
#

Will do. Thanks again.

fallow tartan
#

I just wanted to post an update and let everyone know I figured it out.
I put together a codepen with examples of my code for anyone else this may help.

https://codepen.io/dan-whitehouse/pen/BagmyzW

Additionally... Someone at AWS needs to update that documentation some more because it is incomplete and was very frustrating trying to figure out. Thanks again for your help @wanton furnace

Also, as an aside, for anyone else who is having trouble from time to time with the sandbox triggering after every key stroke lol, I suggest letting the sandbox create the mutations and do a single deploy, then stop the sandbox. Then go to the AWS console and navigate to: AWS AppSync -> APIs -> Your Project -> Functions.

Then search for the function that was created for you (should start like: Fn_Mutation). Then I suggest clicking into it and then going to the Function Code section, and making all of your changes here. Save it, then test, and keep trying until you figure it out. Idk how much time I wasted waiting for the sandbox to keep deploying.

ocean mica
#

Wow. That looks fabulous. I had stumbled into some of your discoveries -- like about the table name -- but not nearly all of it. Something clearly isn't quite ready for prime time. The documentation just isn't there, for one thing (even just explicitly noting what isn't available would be helpful, as there might be alternatives that do work). Of course I understand the Amplify staff needs manage what it has resources to focus on.