Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use arrayUnion in set operation

I am trying to perform FieldValue.arrayUnion() on set(), but it is throwing an Exception. I'm using set instead of update, because I want it to create the document if not exists.

Code (in my case its Batch Write, but I think the principle is same)

WriteBatch batch = db.batch();
MyModel myModel = new MyModel("rwTEPzn9vjyhZCZxFeq8", "Mangesh"); // sample data
batch.set(docRef, FieldValue.arrayUnion(myModel), SetOptions.mergeFields("items"));  // throws exception

Stack trace:

W/System.err: java.lang.NullPointerException: Attempt to invoke virtual method 'com.google.firestore.v1.Value$ValueTypeCase com.google.firestore.v1.Value.getValueTypeCase()' on a null object reference
W/System.err:     at com.google.firebase.firestore.UserDataReader.convertAndParseDocumentData(com.google.firebase:firebase-firestore@@21.4.2:233)
W/System.err:     at com.google.firebase.firestore.UserDataReader.parseMergeData(com.google.firebase:firebase-firestore@@21.4.2:87)
W/System.err:     at com.google.firebase.firestore.WriteBatch.set(com.google.firebase:firebase-firestore@@21.4.2:89)
W/System.err:     at com.abc.AbcActivity.addTrans(AbcActivity.java:604)
W/System.err:     at com.abc.AbcActivity.validateInputs(AbcActivity.java:571)
W/System.err:     at com.abc.AbcActivity.onAddRecord(AbcActivity.java:260)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at android.view.View$DeclaredOnClickListener.onClick(View.java:5989)
W/System.err:     at android.view.View.performClick(View.java:7140)
W/System.err:     at android.view.View.performClickInternal(View.java:7117)
W/System.err:     at android.view.View.access$3500(View.java:801)
W/System.err:     at android.view.View$PerformClick.run(View.java:27351)
W/System.err:     at android.os.Handler.handleCallback(Handler.java:883)
W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:100)
W/System.err:     at android.os.Looper.loop(Looper.java:214)
W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:7356)
W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)
W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)

UPDATE 1: MyModel is a very simple POJO class with couple of strings.

public class MyModel {
    private String id, name;

    public MyModel (String id, String name) {
        this.id = id;
        this.name = name;
    }

    @PropertyName("id")
    public String getId() {
        return id;
    }

    @PropertyName("id")
    public void setId(String id) {
        this.id = id;
    }

    @PropertyName("name")
    public String getName() {
        return name;
    }

    @PropertyName("name")
    public void setName(String name) {
        this.name= name;
    }
}

UPDATE 2: The exception is thrown for String and int values as well. That is, neither FieldValue.arrayUnion("abc") nor FieldValue.arrayUnion(1) works. I have also observed the same behaviour in case of arrayRemove().

UPDATE 3: Here is a screenshot of my db.

DB

UPDATE 4: I tested set outside of batch, directly on the document. It fails. Note that items was emptied before doing this to avoid any type-related conflicts.

docRef.set(FieldValue.arrayUnion("abc"), SetOptions.mergeFields("items"));

Looks like it is impossible to use arrayUnion and arrayRemove with set, despite of the documentation that says: "returns a special value that can be used with set() or update()"

like image 649
Mangesh Avatar asked Oct 25 '25 10:10

Mangesh


1 Answers

Finally, I found a solution. Here is the code:

Map<String, Object> map = new HashMap<>();
map.put("items", FieldValue.arrayUnion(myModel));
batch.set(docRef, map, SetOptions.merge());

This creates the document if not exists and updates items array. Note that, SetOptions.merge() is used instead of SetOptions.mergeFields().

like image 140
Mangesh Avatar answered Oct 28 '25 00:10

Mangesh