3

enter image description here

Above is the structure of collection "networks". What is want to do is add another element in "users" field. It's a HashMap. I want to achieve is Key= xyz@gmail.com and its values {displayName: "Anirudh Kumar", "role":"admin"}.

xyz@gmail.com displayName: "Anirudh Kumar" role: "admin"

I have tried few things but it doesn't seems to work.

1st option

        Map<String, Network.NetworkUser> users = new HashMap<>();
        users.put(email, networkUser);

       db.collection("networks").document("id")
          .update("users",FieldValue.arrayUnion(users));

2nd option

       db.collection("networks").document(userNetwork.getNetworkUid())
                                .set(users,SetOptions.merge());

3rd option

                            db.collection("networks").document(userNetwork.getNetworkUid())
                                .update("users."+email,networkUser);

enter image description here

3rd option takes me closer to answer, but because of dot [.] in an email it creates another row, let me know if somehow this can be avoided.

If anyone can assist me how can I achieve the desired goal, it would be appreciated. Thanks.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
Ankit Ostwal
  • 1,033
  • 3
  • 14
  • 32

2 Answers2

2

None of your attempts work because you are trying to update a document using a Map in which the value is an object of type Network.NetworkUser and this is not possible, because there is no way you can map that object to a HashMap.

What is users property? In fact, is a property of type Map, which contains in terms other HashMaps. So you need to get the document first, get the value of users property, cast to a Map<String, Object> and put inside another HashMap. This new HashMap contains an object with the email address as the key and another HashMap as a value, which again in terms contains two keys with two values. After you add the desired data to the Map, simply write the document back.

If you don't want that behavior, you can simply create a subcollection of users under each (Network.NetworkUser) document.

Alex Mamo
  • 130,605
  • 17
  • 163
  • 193
  • Hi Alex , i didn't got your point of, " get the value of users property, cast to a Map and put inside another HashMap". Do you mean i should get a reference to users property? – Ankit Ostwal Jan 06 '20 at 12:01
  • db.collection("networks").document(userNetwork.getNetworkUid()).get() Do you mean something like this.? My doubts may sound little silly, as i am new to Firestore, so i would appreciate it if you can help me get out of it. – Ankit Ostwal Jan 06 '20 at 12:04
  • Also if you look at option 3, i tried, because of dot [.] i could not get my issue resolved. Otherwise it was a workable solution. – Ankit Ostwal Jan 06 '20 at 12:05
  • Yes, you get the document first using `db.collection("networks").document(userNetwork.getNetworkUid()).get()`, attach a listener and get the value of the `users` property. SInce you cast that value to a `Map`, you can than add another HashMap with the structure that is explained in my answer. – Alex Mamo Jan 06 '20 at 12:06
  • Solution three won't work too since you are using a `Network.NetworkUser` object, In the end, don't forget to write the document back. That's it. – Alex Mamo Jan 06 '20 at 12:08
  • Ok, keep me posted. – Alex Mamo Jan 06 '20 at 12:17
  • Hi Alex, it worked. Thanks man. I invested like 4 hrs behind this before posting it over here. Thanks for the support. – Ankit Ostwal Jan 06 '20 at 12:21
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/205435/discussion-between-ankit-ostwal-and-alex-mamo). – Ankit Ostwal Jan 06 '20 at 12:21
0

This can be useful for someone else, as Alex said in the previous post, the problem is happening because Firestore doesnt know the Object "NetworkUser". So an approach to handle This is to convert the object in a Json String as follows:

1.- Before Insert, create a new Hashmap<String, String>

2.- Iterate over your old Hashmap<String, Object>, and using Gson (or another) do :

        val gson = Gson()
        for ((key, user) in my_old_hashmap) {
            val user  = gson.toJson(user)
            my_new_hashmap[key] = user
        }

3.- Proceed to insert in firestore as you insert any structure.

4.- Then for read this convert again to "your structure" using gson:

for ((key, user_string) in my_new_hashmap) {
      val user  = gson.fromJson(user_string, My_Object_Any::class.java)
       my_old_hashMap[key] = user
        }

TL;DR: Firestore doesn't Know your structure, so the HashMap to insert can be <String, String> or any other primitive Object supported by Firestore.

Dharman
  • 30,962
  • 25
  • 85
  • 135
ZLNK
  • 811
  • 14
  • 17