amplitude / Amplitude-Android

Native Android SDK for Amplitude
MIT License
162 stars 90 forks source link

Unsetting user property that was set with Map doesn't work #313

Closed PattaFeuFeu closed 2 years ago

PattaFeuFeu commented 2 years ago

The SDK allows us to set user properties with a map—via JSONObject—like so:

val userPropertySubProperties = mapOf(
    "foo" to "bar",
    "bar" to "baz"
)
Amplitude.getInstance().Identify().set("user-property-foo", JSONObject(userPropertySubProperties))

This will result in the following user properties being set:

  1. Key: user-property-foo.foo Value: bar
  2. Key: user-property-foo.bar Value: baz

In essence, "sub"-properties are being set.

However, when unsetting user properties, no such function for handling JSONObject (and with it: Maps) exists.

Identify().unset("user-property-foo") does not unset the properties set using the aforementioned code.

Available workaround: Unsetting each sub-property individually, like so:

val userPropertySubProperties = mapOf(
    "foo" to "bar",
    "bar" to "baz"
)
var identify = Identify()
userPropertySubProperties.keys.forEach { key -> 
    identify = identify.unset("user-property-foo.$key") // e.g., "user-property-foo.foo"
}
Amplitude.getInstance().identify(identify)

Expected Behavior

A method to unset sub-properties should exist that allows unsetting properties set via JSONObject. And/or the unset method of Identify should be able to remove all sub-properties previously set via JSONObject.

Current Behavior

When setting a user property with JSONObject payload, for example a map turned into a JSONObject, sub-properties are set on Amplitude. Those cannot easily be unset via the unset method of Identify.

Possible Solution

Option A: Add method that accepts multiple sub-properties to be removed

Option B: Change behaviour of unset to accept a JSONObject (similar to A)

Option C: Change behaviour of unset to, in the end, remove all sub-properties for a given property automatically.

In the case of the example above: When unsetting user-property-foo, user-property-foo as well as user-property-foo.foo and user-property-foo.bar would be unset.

Steps to Reproduce

  1. Set user property with a JSONObject
    val userPropertySubProperties = mapOf(
    "foo" to "bar",
    "bar" to "baz"
    )
    Amplitude.getInstance().identify(Identify().set("user-property-foo", JSONObject(userPropertySubProperties)))
  2. Unset user property with the same name used when setting
    Amplitude.getInstance().identify(Identify().unset("user-property-foo"))
  3. User property is not unset

Environment

bohan-amplitude commented 2 years ago

Hi @PattaFeuFeu ,

Thank you for report the issue here. I have tested the case and it seems like a backend service behavior. Our backend service transfer nested objects in user properties into flatened key. In the example user-property-foo.foo and user-property-foo.bar were two different user properties but user-property-foo was not a key of user properties here. The backend service may support nested object value in the future, but for now unset all keys in nested object seems to be the right way to unset the parent key.