googleapis / nodejs-firestore

Node.js client for Google Cloud Firestore: a NoSQL document database built for automatic scaling, high performance, and ease of application development.
https://cloud.google.com/firestore/
Apache License 2.0
641 stars 149 forks source link

Boolean values defaulting to false in set method #1732

Closed jadonhansen closed 2 years ago

jadonhansen commented 2 years ago

Environment details

Steps to reproduce

I am calling a specific cloud function from the client app. This function is taking a data object and setting it as the property of another object. The final object will be a new firestore document which is created/updated using the .set() method with merge = true.

Inside the original data object there is a field called purchase_usability, a boolean, which must be set as true. However, once saved, the document in firestore always shows it as 'false'.

Check the code below to reproduce. Note that apple_data is the data object I was referring to and contains purchase_usability: true. I have tried this client side using react-native-firestore and it works. Admin sdk or node sdk must have differences?

exports.mergeUserDoc = async function mergeUserDoc(uid, email, apple_data, process) {
    let userObj;

    if (process == "login") {
        userObj = {
            device_os: "ios",
            apple_data: apple_data,
        };
    } else {
        userObj = {
            user_email: email,
            user_creation_datetime: admin.firestore.Timestamp.fromDate(new Date()),
            device_os: "ios",
            apple_data: apple_data,
            gplay_data: { purchase_usability: false },
        };
    }

    try {
        await admin.firestore().collection(FIREBASE_USERS_COLLECTION).doc(uid).set(userObj, { merge: true });
        return userObj;
    } catch (error) {
        logger.error(`mergeUserDoc: ${error}`);
    }
    return null;
}
cherylEnkidu commented 2 years ago

Hi jadonhansen,

Thank you for reporting this issue! I will do some investigation and keep you updated.

jadonhansen commented 2 years ago

Hi @cherylEnkidu I have tested some more and it seems to only happen when the document does not already exist. So in my case, when a user creates an account it will use the user id as the document id, if the doc doesn't exist the set() method will try create it and somehow alters a true to a false boolean value

cherylEnkidu commented 2 years ago

Hi @jadonhansen ,

I wrote some code as following but didn’t reproduce your case successfully. Please let me know if there is any mismatch between our codes.

const ref1 = randomCol.doc('doc1');
    let apple_data = {
      purchase_usability: true
    };
    let userObj = {
      device_os: "ios",
      purchase_usability: false,
      apple_data: apple_data,
    };
    return Promise.all([ref1.set(userObj), { merge: true }])
        .then(() => {
          return ref1.get();
        })
        .then(docs => {
          expect(docs.data()).to.deep.equal({
            device_os: "ios",
            purchase_usability: false,
            apple_data: {purchase_usability: true},
          });
        });
jadonhansen commented 2 years ago

Hi, thanks for the assistance. The only difference is that the purchase_usability: false in userObj is supposed to be a parameter inside of gplay_data object in userObj. But I doubt that will make any difference as we are testing for the truthy value to be in apple_data.

Is this being run in the same environment? Firebase function using node.js v14.18.0 and the admin sdk?

jadonhansen commented 2 years ago

@cherylEnkidu Have you been able to test in that specific environment?

cherylEnkidu commented 2 years ago

Hi @jadonhansen Sorry for the delay, I will keep you updated if I found anything new

jadonhansen commented 2 years ago

My turn to apologize now XD I seem to have introduced a sneaky JS bug client side, along the lines of comparing null values to undefined values. So I can confirm the issue is not with this package at all. Thank you for your time and help!