question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[Firestore] API Feedback – Empty Object Merge Behavior

See original GitHub issue

Environment

  • Operating System version: macOS Catalina 10.15.2
  • Firebase SDK version: 7.17.2
  • Firebase Product: Firestore
  • Node.js version: 12.14.1
  • NPM version: 6.14.7

Problem

It’s been discussed in more than a few other places, but the current behavior of firestore.set('any/document'. { property: {} }, { merge: true }) is unintuitive and dangerous!

ref: https://github.com/firebase/firebase-js-sdk/issues/1371#issuecomment-445066500 ref: https://github.com/firebase/firebase-admin-node/issues/365 ref: https://github.com/mesqueeb/vuex-easy-firestore/issues/73 ref: https://github.com/firebase/firebase-js-sdk/issues/1371 ref: https://github.com/firebase/firebase-js-sdk/issues/1168

We nearly had a production error because of this database API quirk – we caught it through sheer luck. I wanted to flag it again and make the case for changing the behavior in a future major release.

Steps to reproduce:

The Good

firestore.set('any/document'. { property: { foo: 'bar' } }, { merge: true });
firestore.set('any/document'. { property: { biz: 'baz' } }, { merge: true });
console.log(await firestore.doc('any/document').get()).data());
// Expected Log: { foo: 'bar', biz: 'baz' }  👍 
// Actual Log: { foo: 'bar', biz: 'baz' }    😎 

The Bad

firestore.set('any/document'. { property: { foo: 'bar' } }, { merge: true });
firestore.set('any/document'. { property: {} }, { merge: true });
console.log(await firestore.doc('any/document').get()).data());
// Expected Log: { foo: 'bar' } 👍 
// Actual Log: { } 😱 

This is a very easy mistake to make, especially since it it not clearly called out in the docs, and depending on the setup a system may remove keys to patch update based on user input. This behavior forces extra (expensive!) input validation on deep objects that should not be necessary.

I would expect that any destructive operations with { merge: true } must be explicitly set using FieldValue.delete().

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:2
  • Comments:7 (4 by maintainers)

github_iconTop GitHub Comments

1reaction
JarnoRFBcommented, Dec 21, 2021

New firebase user chiming in: I came here because I just tripped over this behavior when updating a document with data from another query that could potentially be empty. I think it definitely makes sense to document the behavior more explicitly. However, I would agree with @amiller-gh that is behavior is really not intuitive and I think it is preferable to provide an intuitive API than to document an unintuitive one.

I would also like to bring algebraic argument: I think most people (including me) think of merging as a kind of addition operation and expect {} to behave as a neutral element. This also makes sense, since merging objects is basically a union of sets, which can be seen as equivalent to addition. In the current API {} is treated as an absorbing element which apparently trips many people off.

1reaction
schmidt-sebastiancommented, Aug 11, 2020

@amiller-gh Thanks for filing this. We have had some lengthy discussions on how to best implement this. While we know that the current “drop on empty” can be surprising, we found it less surprising that simply ignoring empty objects. Since changing the behavior here would be a major breaking change, I don’t think this is realistically going to happen.

We can certainly improve our documentation here. I will use this issue to do so.

Read more comments on GitHub >

github_iconTop Results From Across the Web

firebase/firestore - JavaScript API reference - Google
This API is provided as a preview for developers and may change based on feedback that we receive. Do not use this API...
Read more >
Difference Between Firestore Set with {merge: true} and Update
In the docs it says that using set(object, { merge: true }) will merge the given object with the existing document. The same...
Read more >
Firebase Cloud Firestore Querying Filtering Data for Web
Understanding how queries work on the Firestore Database is one of the ... with the only difference being it has a JavaScript object...
Read more >
@firebase/firestore | Yarn - Package Manager
The Cloud Firestore component of the Firebase JS SDK. ... The Firebase JavaScript SDK implements the client-side libraries used by applications using ...
Read more >
Getting data | Firestore - Google Cloud
Send feedback. On this page ... Source Options; Custom objects ... the resulting document will be empty and calling exists on it will...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found