googleapis / googleapis/google-cloud-node

[FR] expose Preconditions in the set call for the admin API

Open
#7,480 2 comments 0 reactions 1 assignee Claimed by @dconeybe View on GitHub
api: firestore library: nodejs-firestore priority: p3 type: feature request
Dominant language
TypeScript
Stars
3.2k
Forks
712
Avg merge
2d 3h
Merged PRs (30d)
99

Description

(the Firestore Node Admin API folks sent me over here from https://github.com/firebase/firebase-admin-node/issues/1597)

### Describe the problem
The Admin API exposes an `update` method which includes Preconditions. This allows us to specify that a document update call should fail if the DB document was modified after the precondition.updateTime. This is a nice way to make sure that REST API callers don't overwrite documents that were simultaneously modified.

Unfortunately, the `set` method does not expose a way to specify a similar Precondition, which means we can only specify Preconditions when updating an existing document, and not when we want to replace it wholesale.

### Relevant Code:
```typescript
// Setup
const ref = db.doc('/some/path');
const v1 = {foo: 'bar'};
await ref.set(v1);
const t1 = await ref.get().then((d) => d.updateTime);

// I can use preconditions with update
await ref.update({bim: 'baz'}, {lastUpdateTime: t1}); // This will succeed
await ref.update({bim: 'boing'}, {lastUpdateTime: t1}); // This will then fail due to the precondition

// But the result is a merged document. I want to *replace* the document as this is a REST API
await ref.get().then((d) => d.data()); // --> {foo: 'bar', bim: 'baz'} but I want just {bim: 'baz'}

// So we try to use `set` instead
await ref.set({bim: 'baz'}); // but there is no way to specify the precondition above
```

### Workarounds:

- I can manually read the existing document and throw an error myself if the precondition isn't met, but that makes for awkward transactions (which expect to do all reads before any writes).
- I could enumerate top-level fields and spread across them with a FieldValue.delete() overridden by the new document (something like ref.update({...{field1: delete(), field2: delete()}, ...theNewDoc}), but this is also really awkward. While I know my top-level types, enumerating them is hard in typescript (where types are erased at runtime).

(ported over from https://github.com/firebase/firebase-js-sdk/issues/6058 and https://github.com/firebase/firebase-admin-node/issues/1597)

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.