【问题标题】:How to use arrayUnion in set operation如何在集合操作中使用arrayUnion
【发布时间】:2020-06-02 18:02:37
【问题描述】:

我正在尝试在set() 上执行FieldValue.arrayUnion(),但它会引发异常。我使用set 而不是update,因为如果不存在,我希望它创建文档。

代码(在我的例子中是Batch Write,但我认为原理是一样的)

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

堆栈跟踪:

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)

更新 1: MyModel 是一个非常简单的 POJO 类,带有几个字符串。

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;
    }
}

更新 2:Stringint 值也会引发异常。也就是说,FieldValue.arrayUnion("abc")FieldValue.arrayUnion(1) 都不起作用。在arrayRemove() 的情况下,我也观察到了相同的行为。

更新 3:这是我的数据库的屏幕截图。

更新 4: 我在 batch 之外直接在文档上测试了 set。它失败。请注意,items 在执行此操作之前已清空,以避免任何与类型相关的冲突。

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

看起来不可能将arrayUnionarrayRemoveset 一起使用,尽管文档中说:“返回一个可以与set()update() 一起使用的特殊值”

【问题讨论】:

  • 请编辑问题以准确说明myModel 是什么。我们应该有足够的信息来自行重现该问题。
  • @DougStevenson:已更新。为了发布的目的,代码被过度简化了,但它也随之重现。
  • 为了完整起见,您是否尝试过 arrayUnion 的其他参数?只是字符串或数字呢?您是否能够辨别出哪些有效哪些无效的模式?
  • 哪些元素不起作用?
  • @AlexMamo:确切的元素是 POJO,就像 MyModel 但有更多字段;普通的Strings 和ints。没什么特别的。

标签: java android firebase google-cloud-firestore


【解决方案1】:

最后,我找到了解决方案。代码如下:

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

如果不存在则创建文档并更新items 数组。请注意,使用SetOptions.merge() 代替SetOptions.mergeFields()

【讨论】:

  • 我还是想知道为什么SetOptions.mergeFields()不起作用,怎么用,在什么场景SetOptions.mergeFields()合适。
  • 数组中要更新的新值abc在哪里?检查我更新的答案。
  • 您可以使用任何值来代替myModel,不管是字符串、数字还是任何自定义对象。
【解决方案2】:

这些方法调用都不起作用,因为您的 items 数组包含 MyModel 对象而不是字符串或数字。我能想到的最简单的方法是 get that array as a list of MyModel objects (List&lt;MyModel&gt;) 并根据您的需要删除/添加元素。

还请注意,为了从数组中删除整个对象,您应该将整个对象传递给该方法,包括所有字段,而不仅仅是部分数据。

编辑:

arrayUnion 如何知道要更新哪个数组?

它会知道,因为我们需要将数组属性的名称作为第一个参数传递。所以请使用以下代码行:

FirebaseFirestore rootRef = FirebaseFirestore.getInstance();
WriteBatch batch = rootRef.batch();
DocumentReference docRef = rootRef.collection("yourColl").document("docId");
batch.update(docRef, "items", FieldValue.arrayUnion("abc"));
batch.commit();

结果将更新您的 items 数组,其中包含一个新元素 abc

【讨论】:

  • 它也不适用于字符串和数字。检查更新 2。这里真正的问题是,标题为“如何在集合操作中使用 arrayUnion?”。
  • 如果您将存储在 items 数组中的字符串元素和 not MyModel 对象,那么 FieldValue.arrayUnion("abc") 就可以了。如果您将存储在items 整数中,那么 FieldValue.arrayUnion(1) 也可以使用。除非您将完整对象作为参数传递,否则它无法使用实际模式工作。更多信息 here.
  • 不。我从items 中删除了所有元素并尝试了batch.set(docRef, FieldValue.arrayUnion("abc"), SetOptions.mergeFields("items"));。它失败了。
  • 无需将其添加到批处理中,该操作已经是原子的。尝试直接添加,就像docs留的一样。
  • 我正在将此set 与其他写入操作结合起来,因此是批处理。
猜你喜欢
  • 2021-09-03
  • 2020-11-26
  • 1970-01-01
  • 1970-01-01
  • 2023-02-08
  • 2011-06-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多