Amazon DynamoDB · UpdateMultiple
Update or delete every item a filter matches
Every item a filter matches, changed or deleted in one call. DynamoDB reads by partition, so the filter gives one (a customer's orders); ARX finds the items with one query, then writes each by its key in one transaction, conditioned on the filter still matching it.
Set up for this page
The scenarios build on the sample application: SampleContext.cs (the dbContext every sample is given); SampleOutput.cs (Step and Show, which print); SampleContext.Application.cs (dbContext.Service, the application's ARX service); SampleModel.cs (the DynamoDB layout and the schema catalog); SampleContext.Direct.cs (dbContext.Direct); DynamoDirectHelper.cs (the checks behind dbContext.Direct).
dbContext.Direct is the samples' own checking code on the plain driver, not part of ARX: leave it out of your application.
Before scenario 1 the sample runs this, so the service and the rows the scenarios use are there:
var orders = new List<ArxEntity>();
for (var i = 1; i <= 4; i++)
{
var order = new ArxEntity("sales_order");
order["customer_id"] = "C-DF01";
order["order_number"] = $"SO-DF0{i}";
order["status"] = "OPEN";
order["ordered_on"] = "2026-11-11";
order["total"] = i * 40m;
orders.Add(order);
}
await service.CreateMultipleAsync(orders);1 Update by a filter
The customer's small orders cancelled: the GSI1 key moves with the status.
Already in scope: service (ArxDynamoDbService)
var change = new ArxEntity("sales_order");
change["status"] = "CANCELLED";
var filter = new ArxFilterExpression();
filter.AddCondition("customer_id", ArxConditionOperator.Equal, "C-DF01");
filter.AddCondition("total", ArxConditionOperator.LessThan, 100m);
int changed = await service.UpdateMultipleAsync(change, filter);
Console.WriteLine($"{changed} orders cancelled");Check it in the database
A PartiQL statement: run it in NoSQL Workbench, or with aws dynamodb execute-statement --statement, after the code has run.
SELECT "order_number", "status", "total", "GSI1PK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-DF01' AND begins_with("SK", 'ORDER#')Expect: 4 items; SO-DF01 and SO-DF02 (40, 80) CANCELLED with GSI1PK STATUS#CANCELLED, the other two OPEN.
2 Delete by a filter
The cancelled orders deleted by the same kind of filter; the call returns how many went.
Already in scope: service (ArxDynamoDbService)
var filter = new ArxFilterExpression();
filter.AddCondition("customer_id", ArxConditionOperator.Equal, "C-DF01");
filter.AddCondition("status", ArxConditionOperator.Equal, "CANCELLED");
int deleted = await service.DeleteMultipleAsync("sales_order", filter);
Console.WriteLine($"{deleted} cancelled orders deleted");Check it in the database
A PartiQL statement: run it in NoSQL Workbench, or with aws dynamodb execute-statement --statement, after the code has run.
SELECT "order_number", "status" FROM "crm" WHERE "PK" = 'CUSTOMER#C-DF01' AND begins_with("SK", 'ORDER#')Expect: 2 items, SO-DF03 and SO-DF04, both OPEN.
Good to know
A filter that gives no partition key, of the table or an index, is refused (ARX8001): a write never scans. At most 100 items, the most one transaction can write.
The entity carries only the values to set: an id or a key attribute is refused (ARX1001).
Needs ARX.SDK 0.1.0-preview.5 or later.
Run the complete sample
The code above comes from one program, built in a fresh project and run against the database. To run it yourself, here is every file and step.
The program, its files and how to run it
Run it locally
- .NET SDK: .NET SDK 10.0.100 or later 10.0.x (target
net10.0). - Create the project:
Terminal dotnet new console -n ArxSample -f net10.0 cd ArxSample - Install the packages:
Terminal dotnet add package ARX.SDK.DynamoDb --version 1.0.0-rc.1 - Database: a Amazon DynamoDB, or DynamoDB Local for development (tested with DynamoDB Local 2.5.2) database with the sample schema.
- Configuration: set
ARX_SAMPLES_DYNAMODBto its connection string. Nothing is hard-coded. - Source code: add the files of the sample application this sample uses (
SampleContext.cs,SampleOutput.cs,SampleContext.Application.cs,SampleModel.cs,SampleContext.Direct.cs,DynamoDirectHelper.cs), then replaceProgram.csand add the other file below, with the file names shown. - Run it:
Terminal dotnet run - Expected output: below.
The files
Runs the sample. Generated for this page; it reads the connection string from the environment and first remakes the sample database from sample-schema.json.
using ArxSamples.DynamoDb;
using ArxSamples.DynamoDb.Operations.UpdateMultiple.Basics;
// The connection string comes from the environment, never from the code (see "Configure the connection").
var connectionString = Environment.GetEnvironmentVariable("ARX_SAMPLES_DYNAMODB")
?? throw new InvalidOperationException("Set the ARX_SAMPLES_DYNAMODB environment variable to your Amazon DynamoDB connection string.");
var dbContext = new SampleContext(connectionString);
// Every run starts from the sample data: this deletes and makes again what sample-schema.json lists
// (save the file in the project folder, see Get started).
await dbContext.Direct.ResetAsync();
await new Basic2_ByAFilter().RunAsync(dbContext);
The sample, as it is in the repository.
using ARX.SDK;
using ARX.SDK.DynamoDb.Services;
using ARX.SDK.Query;
using ARX.SDK.Services;
using static ArxSamples.DynamoDb.SampleOutput;
namespace ArxSamples.DynamoDb.Operations.UpdateMultiple.Basics;
/// <summary>
/// Every item a filter matches, changed or deleted in one call. DynamoDB reads by partition, so the filter gives one (a
/// customer's orders); ARX finds the items with one query, then writes each by its key in one transaction, conditioned on
/// the filter still matching it.
/// </summary>
/// <remarks>
/// <para>A filter that gives no partition key, of the table or an index, is refused (ARX8001): a write never scans. At most 100 items, the most one transaction can write.</para>
/// <para>The entity carries only the values to set: an id or a key attribute is refused (ARX1001).</para>
/// <para>Needs ARX.SDK 0.1.0-preview.5 or later.</para>
/// </remarks>
public sealed class Basic2_ByAFilter : ISample
{
public string Name => "update-multiple-basics-2-by-a-filter";
public string Title => "Update or delete every item a filter matches";
public async Task RunAsync(SampleContext dbContext)
{
var orders = new List<ArxEntity>();
for (var i = 1; i <= 4; i++)
{
var order = new ArxEntity("sales_order");
order["customer_id"] = "C-DF01";
order["order_number"] = $"SO-DF0{i}";
order["status"] = "OPEN";
order["ordered_on"] = "2026-11-11";
order["total"] = i * 40m;
orders.Add(order);
}
await dbContext.Service.CreateMultipleAsync(orders);
await Scenario1_UpdateByAFilterAsync(dbContext.Service);
await Scenario2_DeleteByAFilterAsync(dbContext.Service);
}
/// <summary>1. The customer's small orders cancelled: the GSI1 key moves with the status.</summary>
private static async Task Scenario1_UpdateByAFilterAsync(ArxDynamoDbService service)
{
Step("1. Update by a filter");
var change = new ArxEntity("sales_order");
change["status"] = "CANCELLED";
var filter = new ArxFilterExpression();
filter.AddCondition("customer_id", ArxConditionOperator.Equal, "C-DF01");
filter.AddCondition("total", ArxConditionOperator.LessThan, 100m);
int changed = await service.UpdateMultipleAsync(change, filter);
Show($"{changed} orders cancelled");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "order_number", "status", "total", "GSI1PK" FROM "crm" WHERE "PK" = 'CUSTOMER#C-DF01' AND begins_with("SK", 'ORDER#')
* -- Expect: 4 items; SO-DF01 and SO-DF02 (40, 80) CANCELLED with GSI1PK STATUS#CANCELLED, the other two OPEN.
* ===========================================================
*/
}
/// <summary>2. The cancelled orders deleted by the same kind of filter; the call returns how many went.</summary>
private static async Task Scenario2_DeleteByAFilterAsync(ArxDynamoDbService service)
{
Step("2. Delete by a filter");
var filter = new ArxFilterExpression();
filter.AddCondition("customer_id", ArxConditionOperator.Equal, "C-DF01");
filter.AddCondition("status", ArxConditionOperator.Equal, "CANCELLED");
int deleted = await service.DeleteMultipleAsync("sales_order", filter);
Show($"{deleted} cancelled orders deleted");
/* ===========================================================
* [DIRECT QUERY CHECK]
* -----------------------------------------------------------
* SELECT "order_number", "status" FROM "crm" WHERE "PK" = 'CUSTOMER#C-DF01' AND begins_with("SK", 'ORDER#')
* -- Expect: 2 items, SO-DF03 and SO-DF04, both OPEN.
* ===========================================================
*/
}
}
Expected output
What dotnet run printed when the sample was verified, on a freshly created sample schema. Ids differ when the tables already hold rows.
> 1. Update by a filter
2 orders cancelled
> 2. Delete by a filter
2 cancelled orders deleted