nodejs-firestore icon indicating copy to clipboard operation
nodejs-firestore copied to clipboard

Updating a nested document with a dynamic path using typescript

Open PWhiddy opened this issue 2 years ago • 11 comments

I have some code which was working great with earlier versions of firestore/typescript, but after updating can't see how firestore expects nested objects to be updated with dynamic paths.

It happily accepts a single string literal like this:

// no type error
const keyPath = "paymentHistory.test";
t.update(userRef, {
  [keyPath]: payment,
});

But strangely this results in a complex type error involving AddPrefixToKeys.

// type error
const keyPath = "paymentHistory." + "test";
t.update(userRef, {
  [keyPath]: payment,
});

The paymentHistory property on the User object is defined like this:

paymentHistory: Record<string, Payment>

I am using package versions:

"firebase-admin": "11.10.1",
"firebase-functions": "4.4.1",
"typescript": "5.2.2"

How can I satisfy the types, when the nested key "test" is a variable and not known at build time?

Thanks!

PWhiddy avatar Aug 28 '23 23:08 PWhiddy

Hi @PWhiddy, thank you for reporting this issue. Could you please provide a full repro of what you are updating, ie, what is the type of t, and userRef? I am suspecting this might be related to this https://github.com/firebase/firebase-js-sdk/issues/5853

milaGGL avatar Aug 29 '23 17:08 milaGGL

Hi! I'm not sure if it's related to that issue. I made a minimal example that fully reproduces this:
src/index.ts

import {firestore} from "firebase-admin";
import {CollectionReference} from "firebase-admin/firestore";

interface MyDoc {
  nestedA: Record<string, number>
  // The issue goes away if nestedB is removed
  nestedB: Record<string, string>
}

const fstore = firestore();

// The type error goes away if the collection
// is not asserted as "MyDoc", but then type safety is lost
const docStore = fstore.collection("all_docs") as CollectionReference<MyDoc>;

const docRef = docStore.doc("test_doc");

const goodKey = "nestedA.test";
const badKey  = "nestedA." + "test";

// works fine
fstore.runTransaction(async (t) => {
  t.update(docRef, {
    [goodKey]: 3,
  });
});

// type error
fstore.runTransaction(async (t) => {
  t.update(docRef, {
    [badKey]: 3,
  });
});

package.json

{
  "name": "test",
  "version": "0.0.1",
  "scripts": {
    "build": "tsc"
  },
  "main": "index.ts",
  "dependencies": {
    "firebase-admin": "^11.10.1"
  },
  "devDependencies": {
    "typescript": "^5.2.2"
  }
}

tsconfig.json

{
  "compilerOptions": {
    "module": "commonjs",
    "outDir": "lib",
    "strict": true,
    "target": "ES2022",
  },
  "include": [
    "src/**/*"
  ],
  "rootDirs": ["./src"]
}

Really I need the nested key "test" to be dynamic, as is allowed by the type definition of MyDoc, but this simpler case of concatenated string literals makes the strangeness more obvious. This code built fine using an earlier version of typescript/firestore from late last year.

Here is a running demo of these files:
https://codesandbox.io/p/sandbox/gallant-banzai-ypz333 repro

PWhiddy avatar Aug 29 '23 18:08 PWhiddy

Hi @PWhiddy, we have recently fixed a similar issue in the firebase-js-sdk: https://github.com/firebase/firebase-js-sdk/pull/7318. We are planning to port the changes to nodejs-firestore, but I cannot provide an estimated timeline for it. This is added to our backlog along with other tasks. Rest assured, I'll keep you posted on any updates to this thread.

Google internal users please see b/298394991.

milaGGL avatar Aug 31 '23 14:08 milaGGL

Internally tracked by b/311751201.

ehsannas avatar Nov 20 '23 18:11 ehsannas

Any update on this? it's stopping us upgrading past v4

VictorLeach96 avatar Apr 17 '24 20:04 VictorLeach96

Any update on this?

Volna13 avatar Jun 19 '24 10:06 Volna13