# UpdateMultiple with ARX.SDK on MongoDB

## What an UpdateMultiple does

| Rule | On MongoDB |
|---|---|
| Many entities | UpdateMultiple is all or nothing, in a transaction; the same entity or the same match values twice is ARX1001 |
| By a filter | `UpdateMultipleAsync(values, filter)` and `DeleteMultipleAsync(table, filter)`: one `updateMany` or `deleteMany` in a transaction, returning the count; no id in the values, an empty filter needs `AllRows` (Basic2). From 0.1.0-preview.5 |

## The samples

Every UpdateMultiple sample, in reading order. Each scenario shows the code (verified against MongoDB) and the mongosh query that checks what it did. `service` is the application's `ArxMongoDbService`; values marked "In scope" come from earlier in the sample. What the samples' code refers to beyond the packages (SampleCatalog.cs, `dbContext`) is in the sample application file, arx-mongodb-sample-application.md.

### Update many records in one call

Basics 1 of UpdateMultiple.

Many documents in one call, all or nothing, in two scenarios: a different value for each document, and a list with one id no document has, where none of them changes.

Good to know:

UpdateMultiple runs in a transaction, which MongoDB offers on a replica set (one node is enough) or a sharded cluster; on a standalone server it is refused rather than half done. Each entity writes only the fields it sets.

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.MongoDb.Services;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var accounts = new List<ArxEntity>();
foreach (var number in new[] { "ACC-M921", "ACC-M922", "ACC-M923" })
{
    var account = new ArxEntity("account");
    account["name"] = "Many updates " + number;
    account["account_number"] = number;
    account["employee_count"] = 10;
    accounts.Add(account);
}
var ids = await service.CreateMultipleAsync(accounts);
```

#### 1. A value per document

One entity per document, each with its own value: the call returns how many changed.

In scope: `service` (ArxMongoDbService), `ids` (IReadOnlyList<ArxRecordId>).

```csharp
var changes = new List<ArxEntity>();

for (var i = 0; i < ids.Count; i++)
{
    var change = new ArxEntity("account") { RecordId = ids[i] };
    change["employee_count"] = 100 + i;
    changes.Add(change);
}

int changed = await service.UpdateMultipleAsync(changes);

Console.WriteLine($"{changed} documents changed in one call");
```

Check it in the database:

```sql
db.account.find({ account_number: { $in: ["ACC-M921", "ACC-M922", "ACC-M923"] } }, { account_number: 1, employee_count: 1 }).sort({ account_number: 1 })
```

Expect: 3 documents, employee_count 100, 101, 102.

#### 2. All or nothing

The second id belongs to no document: RecordNotFound, and the first document keeps its value too.

In scope: `service` (ArxMongoDbService), `existing` (ArxRecordId).

```csharp
var first = new ArxEntity("account") { RecordId = existing };
first["employee_count"] = 999;

var missing = new ArxEntity("account");
missing["account_id"] = "65a000000000000000000000";
missing["employee_count"] = 999;

try
{
    await service.UpdateMultipleAsync(new[] { first, missing });
}
catch (ArxException exception) when (exception.Code == ArxErrorCode.RecordNotFound)
{
    Console.WriteLine(exception.Message);
}
```

Check it in the database:

```sql
db.account.find({ account_number: "ACC-M921" }, { employee_count: 1 })
```

Expect: employee_count 100 (not 999).

### Update or delete every document a filter matches

Basics 2 of UpdateMultiple.

Every document a filter matches, changed or deleted in one call: one updateMany (or deleteMany) with the filter as a query document, in a transaction, so a document refused half-way leaves every document as it was.

Good to know:

The filter takes the operators of a query on the collection's own fields; values are never read as query operators.

The entity carries only the values to set: an id or _id is refused (ARX1001), and so is an empty filter unless new ArxFilterWriteOptions { AllRows = true } is passed.

Needs ARX.SDK 0.1.0-preview.5 or later, and a replica set (one node is enough).

Usings:

```csharp
using ARX.SDK;
using ARX.SDK.MongoDb.Services;
using ARX.SDK.Query;
using ARX.SDK.Services;
```

Set up by the sample before its scenarios:

```csharp
var accounts = new List<ArxEntity>();
for (var i = 1; i <= 5; i++)
{
    var account = new ArxEntity("account");
    account["name"] = $"Filter update {i}";
    account["account_number"] = $"ACC-MF0{i}";
    account["employee_count"] = i * 5;
    account["status"] = "ACTIVE";
    accounts.Add(account);
}
await service.CreateMultipleAsync(accounts);
```

#### 1. Update by a filter

Small accounts put on hold with one updateMany.

In scope: `service` (ArxMongoDbService).

```csharp
var change = new ArxEntity("account");
change["status"] = "ON_HOLD";

var filter = new ArxFilterExpression();
filter.AddCondition("account_number", ArxConditionOperator.BeginsWith, "ACC-MF0");
filter.AddCondition("employee_count", ArxConditionOperator.LessThan, 15);

int changed = await service.UpdateMultipleAsync(change, filter);

Console.WriteLine($"{changed} accounts put on hold");
```

Check it in the database:

```sql
db.account.find({ account_number: /^ACC-MF0/ }, { account_number: 1, employee_count: 1, status: 1 }).sort({ account_number: 1 })
```

Expect: 5 documents; ACC-MF01 and ACC-MF02 (5 and 10 employees) ON_HOLD, the other three ACTIVE.

#### 2. Delete by a filter

The accounts on hold deleted with one deleteMany; the call returns how many went.

In scope: `service` (ArxMongoDbService).

```csharp
var filter = new ArxFilterExpression();
filter.AddCondition("account_number", ArxConditionOperator.BeginsWith, "ACC-MF0");
filter.AddCondition("status", ArxConditionOperator.Equal, "ON_HOLD");

int deleted = await service.DeleteMultipleAsync("account", filter);

Console.WriteLine($"{deleted} accounts deleted");
```

Check it in the database:

```sql
db.account.find({ account_number: /^ACC-MF0/ }, { account_number: 1, status: 1 }).sort({ account_number: 1 })
```

Expect: 3 documents, ACC-MF03 to ACC-MF05, all ACTIVE.

