Sync Function: "null" equals "undefined"

I was working on a sync function for my sync gateway (1.5.1 community docker image) when I stumbled on a very weird Javascript issue.

Test Document (created/updated in Couchbase Webinterface, Sync Gateway uses continuous import):

 {
     "nullProperty": null,
     "type": "null_test"
 }

Test Sync Function:

function sync(doc, oldDoc) {
    if(doc.type === "null_test"){
        for(property in doc){
            console.log(property + ": " + doc[property] + " " + typeof doc[property]);
            if(typeof doc[property] === "undefined"){
                console.log("null set for " + property);
                doc[property] = null;
            }
            console.log(property + ": " + doc[property] + " " + typeof doc[property]);
        }                    
    }
}

When I update the document, I get this output in the Sync Gateway log:

_id: test string
_id: test string
nullProperty: undefined undefined
null set for nullProperty
nullProperty: undefined undefined
type: null_test string
type: null_test string
_rev: 3-ab6fc88e2aa488cbc4c163ffaf0b2ed3 string
_rev: 3-ab6fc88e2aa488cbc4c163ffaf0b2ed3 string

When I test the same JS code with a local installation of the Otto JS interpreter (at git revision 5282a5a45ba989692b3ae22f730fa6b9dd67662f) I get this result:

_id: test string
_id: test string
nullProperty: null object
nullProperty: null object
type: null_test string
type: null_test string
_rev: 2-5c4824fe23d46aef1a51b126813ac9a4 string
_rev: 2-5c4824fe23d46aef1a51b126813ac9a4 string

As you can see, in this case the “nullProperty” has the correct “null” value with the type “object”.
In the context of the Sync Gateway, properties that have the value “null” are defined, but have an undefined value. An even when setting them in JS explicitly to “null” the operation is ignored (as a sanity check I set the property to a string value instead of null, which worked)

Am I missing something here or is it correct that “null” is a defined property with “undefined” value in the sync function?

1 Like

@fruel thanks for reporting. I filed a Sync Gateway issue for this:

you can track it via the Github “Subscribe” button, and feel free to comment on the issue if you have anything to add.

The issue Traun filed will track not having null interpreted as expected in the first place. The reason the assignment doc[property] = null; doesn’t work is because documents are immutable in the sync function.

@traun thanks for filing the GitHub issue.

@hod.greeley I was under the assumption as well that “doc” and “oldDoc” might be immutable in the sync function. However, when you try to assign a string instead of null to a property, it works fine: (tested with same setup as explained in the first post)

console.log(property + ": " + doc[property] + " " + typeof doc[property]);
doc[property] = "a";
console.log(property + ": " + doc[property] + " " + typeof doc[property]);

Output:

nullProperty: undefined undefined
nullProperty: a string

Yes, sorry, I left off more testing I did. It seems that the doc will show the string as having been set in the sync function and SG admin console, but it doesn’t actually persist it. Apparently the in-memory version of the doc on SG allows the change. So it’s a bit of a bug that setting something like a string appears to succeed, but really doesn’t. I’ll look at filing an issue for that too.

Yeah I did not expect that changes to “doc” will persist to the database.
I tried setting a property manually to “null” in an attempt to work around the “null property is undefined” issue.

Yeah, understood. Are you ok tracking the issue on github? If so I will leave a final message with a pointer to it and close the topic.

Yes GitHub is fine for me. Thanks for the help.

Issue: Unable to differentiate between null and missing fields in the sync function tracked here: https://github.com/couchbase/sync_gateway/issues/3432

Issue: Mutations in sync function appear to succeed tracked here: https://github.com/couchbase/sync_gateway/issues/3445