CosmosDB's Bulk Upsert Responds with 400
See original GitHub issue- Package Name: @azure/cosmos
- Package Version: 3.9.5
- Operating system: WSL Ubuntu 18.04
- nodejs
- version: 10.23.3
- browser
- name/version:
- typescript
- version: 4.2.3
- Is the bug related to documentation in
- README.md
- source code documentation
- SDK API docs on https://docs.microsoft.com
Describe the bug Using the bulk upsert option in a manner similar to what is proposed in #14128 (thanks for showing this!) fails for upsert.
To Reproduce Steps to reproduce the behavior:
- Set up some code like:
const { database } = await client.databases
.createIfNotExists({ id: someDatabaseName });
const { container } = await client
.database(database.id)
.containers.createIfNotExists({ id: someContainerName, partitionKey: chosenPartition }); //partitionKey in this example was "/key"
//...
const operations = [
{
operationType: azcosmos.BulkOperationType.Create,
resourceBody: { "name": "somethingelse", "key": "A" }
},
{
operationType: azcosmos.BulkOperationType.Upsert,
partitionKey: "U",
resourceBody: { "name": "other1", "key": "U" }
},
];
console.log(operations);
const response = await container.items.bulk(operations);
console.log(response);
- Run this code.
- See the response:
[ { statusCode: 201,
requestCharge: 6.285714285714286,
eTag: '"someEtag"',
resourceBody:
{ name: 'somethingelse',
key: 'A',
id: 'some-uuid',
_rid: '...',
_self: '...',
_etag: '"..."',
_attachments: '...',
_ts: ... } },
{ statusCode: 400, requestCharge: 0 } ]
Expected behavior If this fails for a 400 reason, I would love to know specifically which one. The options listed in the docs don’t seem to apply in my case, but it’s hard to tell what it’s failing for if that’s not bubbled up with the status code. Even more ideal is not getting a 400 at all. Creating and reading work as expected, but FWIW I haven’t checked deleting.
Based on the source code, I’d make a few assumptions:
- the inclusion of the partition key is an optional argument based on the definition
- In the case of not including it, the result that I got was still a 400
- because Cosmos DB is schema-less, I would theoretically be able to have the example operations have different contents inside.
- On the portal if an item is added without the partition key, there is no fuss.
- If I change the contents to something arbitrary:
const operations: [
{
operationType: azcosmos.BulkOperationType.Create,
resourceBody: { "name": "somethingelse", "key": "A" }
},
{
operationType: azcosmos.BulkOperationType.Upsert,
partitionKey: "U",
resourceBody: { "name": "other1", "toot": "turtle" }
},
]
… the typescript will not compile:
⨯ Unable to compile TypeScript:
index.ts:159:53 - error TS2345: Argument of type '({ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; } | { operationType: "Upsert"; partitionKey: string; resourceBody: { name: string; toot: string; key?: undefined; }; })[]' is not assignable to parameter of type 'OperationInput[]'.
Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; } | { operationType: "Upsert"; partitionKey: string; resourceBody: { name: string; toot: string; key?: undefined; }; }' is not assignable to type 'OperationInput'.
Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; }' is not assignable to type 'OperationInput'.
Type '{ operationType: "Create"; resourceBody: { name: string; key: string; toot?: undefined; }; partitionKey?: undefined; }' is not assignable to type 'CreateOperationInput'.
Types of property 'resourceBody' are incompatible.
Type '{ name: string; key: string; toot?: undefined; }' is not assignable to type 'JSONObject'.
Property '"toot"' is incompatible with index signature.
Type 'undefined' is not assignable to type 'JSONValue'.
159 const response = await container.items.bulk(operations);
… which seemingly is failing on the “create” Operation. It’s a bit confusing since the create operation wasn’t what was changed.
Screenshots If applicable, add screenshots to help explain your problem.
Additional context
It would be great to have documentation about the different acceptable ways to perform operations given specific data. If Upsert expects a resourceBody
to look either like XYZ or ABC, and Create expects QRS only, etc . In the signature would be fine but even better would be in the docs.
Issue Analytics
- State:
- Created 3 years ago
- Comments:6 (5 by maintainers)
Top GitHub Comments
release 3.10.2 should autogenerate IDs for
Upsert
operations in bulk now@mindlessroman The 400 error is caused by this PR not being released yet - I kicked off a release but it failed and didn’t rerun it, I’ll get that out now. Unfortunately, we only get the response codes back from bulk failures.
As for the compilation failures when you use “toot”, that seems to either be from an old build or from the type being wrong.
The type on the left above doesn’t seem like what you actually want it to be (feel free to import
OperationInput
as a type and use that). In my experimenting, the body I pass tocontainer.items.upsert()
works for theresourceBody
of bulk. I think it’s the same issue with the type not matching what bulk expects. I have a working test case that uses “toot” as a key