简体   繁体   English

如何从 Firestore 获取数组?

[英]How to get an array from Firestore?

I have the data structure illustrated below stored in Cloud Firestore.我将如下所示的数据结构存储在 Cloud Firestore 中。 I want to save the dungeon_group which is an array of strings stored in Firestore.我想保存dungeon_group ,它是一个存储在 Firestore 中的字符串数组。

I have difficulty in getting the data and stored as an array.我很难获取数据并存储为数组。 I am just able to get a weird string but any method to store as a string array?我只能得到一个奇怪的字符串,但是有什么方法可以存储为字符串数组? Below is the code I used.下面是我使用的代码。

I am able to achieve this in Swift as follow, but not sure how to do the same in Android.我能够在 Swift 中实现这一点,如下所示,但不确定如何在 Android 中做到这一点。

在此处输入图片说明

Swift:迅速:

Firestore.firestore().collection("dungeon").document("room_en").getDocument { 
    (document, error) in
    if let document = document {
        let group_array = document["dungeon_group"] as? Array ?? [""]
        print(group_array)
    }    
}

Java Android: Java安卓:

FirebaseFirestore.getInstance().collection("dungeon")
                 .document("room_en").get()
                 .addOnCompleteListener(new 
                     OnCompleteListener<DocumentSnapshot>() {
                     @Override
                     public void onComplete(@NonNull Task<DocumentSnapshot> task) {
                         DocumentSnapshot document = task.getResult();
                         String group_string= document.getData().toString();
                         String[] group_array = ????
                         Log.d("myTag", group_string);
                     }
                 });

Console output as the follow:控制台输出如下:

{dungeon_group=[3P, Urgent, Mission Challenge, Descended, Collaboration, Daily, Technical, Normal]} {dungeon_group=[3P,紧急,任务挑战,降临,协作,日常,技术,普通]}

When you call DocumentSnapshot.getData() , it returns a Map.当您调用DocumentSnapshot.getData() 时,它会返回一个 Map。 You're just calling toString() on that map, which is going to give you a dump of all the data in the document, and that's not particularly helpful.您只是在该地图上调用 toString() ,这将为您提供文档中所有数据的转储,这并不是特别有用。 You need to access the dungeon_group field by name:您需要按名称访问dungeon_group字段:

DocumentSnapshot document = task.getResult();
List<String> group = (List<String>) document.get("dungeon_group");
  • edit: syntax error in typecasting编辑:类型转换中的语法错误

There are two solutions for your problem, one, you can cast the value from your document in the next way:您的问题有两种解决方案,一种是您可以通过以下方式从文档中转换值:

DocumentSnapshot document = task.getResult();
List<String> dungeonGroup = (List<String>) document.get("dungeon_group");

Or, and I would recommend you this solution because there is always a possibility that your model will change when you are developing your app .或者,我会向您推荐这个解决方案,因为在您开发应用程序时,您的模型总是有可能发生变化 This solution is just model everything in Firebase POJO's even if they have just one parameter:此解决方案只是对 Firebase POJO 中的所有内容进行建模,即使它们只有一个参数:

public class Dungeon {

    @PropertyName("dungeon_group")
    private List<String> dungeonGroup;

    public Dungeon() {
        // Must have a public no-argument constructor
    }

    // Initialize all fields of a dungeon
    public Dungeon(List<String> dungeonGroup) {
        this.dungeonGroup = dungeonGroup;
    }

    @PropertyName("dungeon_group")
    public List<String> getDungeonGroup() {
        return dungeonGroup;
    }

    @PropertyName("dungeon_group")
    public void setDungeonGroup(List<String> dungeonGroup) {
        this.dungeonGroup = dungeonGroup;
    }
}

Remember that you can use the Annotation @PropertyName to avoid call your variables in the same way that your value in the database.请记住,您可以使用 Annotation @PropertyName 来避免以与您在数据库中的值相同的方式调用您的变量。 Doing it in this way finally you can just do:以这种方式最终做到这一点,您可以这样做:

DocumentSnapshot document = task.getResult();
Dungeon dungeon= toObject(Dungeon.class);

Hope that it will help you!希望它会帮助你! Happy coding!快乐编码!

If you want to get the entire dungeon_group array you need to iterate over a Map like this:如果你想获得整个dungeon_group数组,你需要像这样迭代Map

Map<String, Object> map = documentSnapshot.getData();
for (Map.Entry<String, Object> entry : map.entrySet()) {
    if (entry.getKey().equals("dungeon_group")) {
        Log.d("TAG", entry.getValue().toString());
    }
}

But note, even if the dungeon_group object is stored in the database as an array, entry.getValue() returns an ArrayList and not an array.但请注意,即使dungeon_group对象作为数组存储在数据库中, entry.getValue()返回一个ArrayList不是数组。

A better approach for you would be if you consider this alternative database structure, in which each group is the key in a Map and all values are set to the boolean true :如果您考虑这种替代数据库结构,对您来说更好的方法是,其中每个group都是Map的键,并且所有值都设置为布尔值true

dungeon_group: {
    3P: true,
    Urgent: true,
    Mission Chalange: true
    //and so on
}

Using this structure you'll also be able to query it based on the property that exists within the dungeon_group map, otherwise as in the official documentation :使用此结构,您还可以根据dungeon_group地图中存在的属性查询它,否则如官方文档中所示

Although Cloud Firestore can store arrays, it does not support querying array members or updating single array elements.虽然 Cloud Firestore 可以存储数组, it does not support查询数组成员或更新单个数组元素。

Edit 13 Jan 2021: 2021 年 1 月 13 日编辑:

If instead of an array of String values you would have had an array of objects, then you can map that array of objects to a List of custom objects, as explained in the following article:如果您有一个对象数组而不是字符串值数组,那么您可以将该对象数组映射到自定义对象列表,如以下文章中所述:

Edit 13 Aug 2018: 2018 年 8 月 13 日编辑:

According to the updated documentation regarding array membership , now it is possible to filter data based on array values using whereArrayContains() method.根据有关数组成员资格的更新文档,现在可以使用whereArrayContains()方法基于数​​组值过滤数据。 A simple example would be:一个简单的例子是:

CollectionReference citiesRef = db.collection("cities");
citiesRef.whereArrayContains("regions", "west_coast");

This query returns every city document where the regions field is an array that contains west_coast.此查询返回每个城市文档,其中区域字段是包含 west_coast 的数组。 If the array has multiple instances of the value you query on, the document is included in the results only once.如果数组具有您查询的值的多个实例,则该文档仅包含在结果中一次。

Since Your document looks like this "dongeon_group=[SP, urgent, missinon challenge,...] when you convert it to string, say via String.valueOf(document.getData())由于您的文档看起来像这样"dongeon_group=[SP, urgent, missinon challenge,...]当您将其转换为字符串时,例如通过String.valueOf(document.getData())

I think another way to simply achieve this is by unpacking the document right away into a string of array as follows:我认为另一种简单地实现这一点的方法是将文档立即解压缩为一串数组,如下所示:

String[] unpackedDoc = document.getData().entrySet().toArray()[0].toString().split("=")[1].split(",");

Explanation解释

The document is gotten from documentSnapshot.getDocuments() which return a list containing you documents.document是从documentSnapshot.getDocuments() ,它返回一个包含您的文档的列表。

Since your documents, from the firestore, seem to be nested, calling the document.getData() will return the list, a list with single element of course, of your document.由于您的来自 firestore 的文档似乎是嵌套的,因此调用document.getData()将返回您的文档的列表,当然是一个包含单个元素的列表。 document.getData().entrySet() will make the document ready to be converted to array (you can't do that with getData() alone) also containing single element. document.getData().entrySet()将使文档准备好被转换为数组(你不能单独使用 getData() 这样做)也包含单个元素。 Accessing the single element document.getData().entrySet().toArray()[0] and then converting it to string, document.getData().entrySet().toArray()[0].toString() will leave with a string that you can then split (using the = found in the string) and then take the second part.访问单个元素document.getData().entrySet().toArray()[0]然后将其转换为字符串, document.getData().entrySet().toArray()[0].toString()将离开然后可以拆分的字符串(使用字符串中的= ),然后取出第二部分。 The second part can also be split into an array containing the values of your document.第二部分也可以拆分为包含文档值的数组。

Since this solution convert one element at a time, you can wrap it within a loop so you can convert all the documents available.由于此解决方案一次转换一个元素,您可以将其包装在一个循环中,以便您可以转换所有可用的文档。

For example:例如:

for(DocumentSnapshot document :documentSnapshot.getDocuments()){ String[] unpackedDoc = document.getData().entrySet().toArray()[0].toString().split("=")[1].split(","); //do something with the unpacked doc

}

How I archive this in my Production app.我如何在我的生产应用程序中存档。

Global Declare全球申报

private final FirebaseFirestore FIRE_STORE_DB;

Reference参考

this.FIRE_STORE_DB = FirebaseFirestore.getInstance();

Collection Method征收方式

 public CollectionReference getCOLLECTION_REF() {
    return FIRE_STORE_DB.collection(Global.COLLECTION_USER);
}

My recuirment is fetch last index of arrays time to current time if it equal return false.如果等于返回false,我的recuirment是获取数组的最后一个索引时间到当前时间。

public void dailyCheck(String UID, OnCheckIn onCheckIn) {
    getCOLLECTION_REF().document(UID).get().addOnSuccessListener(documentSnapshot -> {
        if (documentSnapshot.exists()) {
            List< String > dateList = (List< String >) documentSnapshot.get(FIELD_DAILY_CHECK_IN);
            if (dateList != null) {
                String lastDate = dateList.get(dateList.size() - 1);
                if (!lastDate.equals(getCurrentTimeStamp())) {
                    onCheckIn.todayCheckIn(false);
                } else {
                    Log.e(TAG, "LAST DATE EQUAL ---------------> RETURN");
                    onCheckIn.todayCheckIn(true);
                }
            } else {
                Log.e(TAG, "DATE LIST ---------------> NULL RETURN");
            }

        } else {
            Log.e(TAG, "LOGIN DATE NOT EXIST ---------------> checkInDate");
        }
    });
}

How I get it in my Activity我如何在我的活动中获得它

public interface OnCheckIn {
    void todayCheckIn(boolean check);
}

Below - How I call it下面 - 我怎么称呼它

dbHelper.dailyCheck(CURRENT_USER, check -> {
        if (!check) {
            // todo
        } else {
            // 
        }
    });

Notes - This dbHelper is a class name ->If you have any question about this answer please comment below注释 - 这个 dbHelper 是一个类名->如果你对这个答案有任何疑问,请在下面评论

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM