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/
#✅ - Batch Delete and Need for More and Better Examples of Custom Queries and Mutations
20 messages · Page 1 of 1 (latest)
I am looking for the same
Hmmm... is the implication that if you want to do anything even mildly advanced that you have to define a customType and all the queries and mutations you need -- and not rely on what Amplify generates? Seems like it. I'm just beginning to read this.
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.
Yes, you can create the file at amplify/data/batchDeleteItem.js or similar.
✅ - 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
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
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.
@fallow tartan
There are 3 steps to make this happen:
- Define a function handler in your schema
- Create the function handler to batch delete
- 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
- 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()),
- 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];
}
- 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
Thanks Steven. I'll give this a try. I've also been stuck for a few days, so I appreciate the help. 🙂
@fallow tartan lmk if you can't figure it out
Will do. Thanks again.
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.
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.