googleapis / googleapis/google-cloud-node
FieldValue.increment() is not working as expected on subfields of a map
- Dominant language
- TypeScript
- Stars
- 3.2k
- Forks
- 712
- Avg merge
- 2d 3h
- Merged PRs (30d)
- 99
Description
Thanks for stopping by to let us know something could be better!
**PLEASE READ**: If you have a support contract with Google, please create an issue in the [support console](https://cloud.google.com/support/) instead of filing on GitHub. This will ensure a timely response.
1) Is this a client library issue or a product issue?
I think it's probably something that should be at-least handled by this library.
2) Did someone already solve this?
- Search the issues already opened: https://github.com/googleapis/nodejs-firestore/issues ✅
- Search the issues on our "catch-all" repository: https://github.com/googleapis/google-cloud-node ✅
- Search or ask on StackOverflow (engineers monitor these tags): http://stackoverflow.com/questions/tagged/google-cloud-platform+node.js ✅
3) Do you have a support contract?
Nope
If the support paths suggested above still do not result in a resolution, please provide the following details.
#### Environment details
- OS: Mac
- Node.js version: 18.16.0
- npm version: 9.5.1
- `@google-cloud/firestore` version: ^6.8.0
#### Steps to reproduce
The `FieldValue.increment()` function does not work as expected on subFields of a map value. Given this data structure of the object in the database:
```ts
{
amount: 1,
map: {
amount: 1
}
}
```
If I run this code:
```ts
await docRef.update({
amount: FieldValue.increment(2),
sub: {
amount: FieldValue.increment(2)
}
})
```
The data in the database ends up being:
```ts
{
amount: 3,
map: {
amount: 2
}
}
```
It would seem that incrementing using this object syntax does increment on top-level keys, but "sets" the value of subfields of maps to the exact increment value, rather than incrementing.
To me this feels like the incorrect behaviour - I would firstly expect that `map.amount` would be `3`, OR expect the SDK to throw an error as it does when using `FieldValue.delete()` on a subfield of a map in this way.
The "workaround" is to use dot-notation strings as keys on the top level of the object like so:
```ts
await docRef.update({
amount: FieldValue.increment(2),
'sub.amount': FieldValue.increment(2)
})
```
This does work as expected and the data in the db ends up being:
```{
amount: 3,
map: {
amount: 3
}
}
```
This issue has been observed in SO here:
https://stackoverflow.com/questions/56427582/how-to-use-fieldvalue-increment-on-the-property-of-an-object-type-document-fie
It feels like this warrants an issue and a change to how the sdk handles this to bring it in line with how it handles `FieldValue.delete()` on subfields of a map where for example, this code throws an error:
```ts
await docRef.update({
amount: FieldValue.increment(2),
sub: {
amount: FieldValue.delete()
}
})
```
Error:
> Update() requires either a single JavaScript object or an alternating list of field/value pairs that can be followed by an optional precondition. Value for argument "dataOrField" is not a valid Firestore value. FieldValue.delete() must appear at the top-level and can only be used in update() or set() with {merge:true} (found in field "sub.amount")
It took a wilte to figure out what was going on here, and can be especially confusing when incrementing from `0` because it _seems_ like the first request works, but then subsequent requests do not behave as expected. Eg:
Db is:
```ts
{
amount: 0,
map: {
amount: 0
}
}
```
Run:
```ts
await docRef.update({
amount: FieldValue.increment(1),
sub: {
amount: FieldValue.increment(1)
}
})
```
Db is now:
```
{
amount: 1,
map: {
amount: 1
}
}
```
Which seems like it works... But if you run the exact same code again:
```ts
await docRef.update({
amount: FieldValue.increment(1),
sub: {
amount: FieldValue.increment(1)
}
})
```
Now the data in the db ends up being incorrect:
```
{
amount: 2,
map: {
amount: 1
}
}
```
Contributor guide
Assessment
This issue has not been assessed yet.