返回

Firestore 数据结构调整与 API 适配指南

java

Firestore 结构调整与 API 适配

本文将探讨如何调整 Firestore 数据结构,并适配外部 API 的数据调用方式。我们将分析现有代码,并提供解决方案来实现新的 Firestore 结构设计,同时处理 API 数据不包含所需字段的问题。

问题分析

目前代码的目标是从 TheSportsDB API 获取赛事数据,并存储到 Firestore 中。代码已经实现了根据运动、联赛和赛季筛选赛事数据的功能,并能将赛事数据存储到旧的 Firestore 结构中。然而,新的 Firestore 结构引入了 Matchday 层级,而 API 默认并没有返回 Matchday 信息,需要进行适配和调整。

现有的 Firestore 结构:

Root: events/{selectedSport}/leagues/{selectedLeague}/seasons/{selectedSeason}/matchdays/{idEvent}

新的 Firestore 结构目标:

Root: events/{LeagueName: league name, selectedLeagueId}/seasons/{SeasonName: seasonID}/matchdays/{Matchday: matchdayID}/matches/{Match: matchID}

TheSportsDB API 调用方式:

https://www.thesportsdb.com/api/v1/json/xxx/eventsseason.php?id={selectedLeagueId}&s={season}&round={strMatchday}

关键问题在于:

  1. API 并不直接返回 Matchday 信息,需要通过其他方式获取或推断。
  2. 代码需要调整,以适应新的 Firestore 结构,并能将赛事数据正确地存储到新的层级结构中。

解决方案

为了解决以上问题,我们可以采用以下方案:

  1. 修改 API 调用,增加 strMatchday 参数: 虽然 API 不直接返回 Matchday,但我们可以假设它支持按 Matchday 筛选,并在 API 调用中增加 round 参数来传递 Matchday 值。如果 API 不支持此参数,则需要寻找其他方式获取或推断 Matchday 信息,例如根据赛事日期或其他信息进行分组。
  2. 在 Event 类中添加 matchday 字段: 在 Java 的 Event 类中增加一个 matchday 字段,用于存储 Matchday 值。
  3. 修改数据存储逻辑,适应新的 Firestore 结构: 修改 fetchEvents 方法,使其能根据新的 Firestore 结构存储数据,并在数据中添加 matchday 信息和顺序信息。

具体步骤与代码修改

1. 修改 API 调用并增加 matchday 字段

假设 TheSportsDB API 支持 round 参数,我们可以修改 fetchEvents 方法中的 API 调用,增加 strMatchday 参数:

private void fetchEvents(String leagueID, String season, String matchday) { // Add matchday as a parameter
    String url = BASE_URL + "eventsseason.php?id=" + leagueID + "&s=" + season + "&round=" + matchday;
    // ... other codes remains unchanged ...
}

更新 Event 类,添加 matchday 字段:

public class Event {
    // ... other fields ...
    private String matchday;

    public Event() {}

    public Event(String sport, String league, String season, String matchday) {
        //... other initializations ...
        this.matchday = matchday;
    }
    
    // ... other getters and setters ...

    public String getMatchday() {
        return matchday;
    }

    public void setMatchday(String matchday) {
        this.matchday = matchday;
    }
}

2. 修改数据存储逻辑

fetchEvents 方法中,我们需要根据新的 Firestore 结构调整数据存储逻辑,并在数据中添加 matchday 字段和 order of arrival 字段。考虑到 API 不直接提供 matchday 数据,我们需要根据实际情况处理:

  • 如果 API 支持 round 参数筛选 , 我们可以直接使用传入的 matchday 参数。
  • 如果 API 不支持 , 则需要根据日期或其他逻辑自行生成 matchday 信息,这里我们采用 API 调用时传入的 Matchday 信息,同时增加一个字段 "order of arrival"来记录数据到达顺序:
private void fetchEvents(String selectedLeagueID, String selectedSeason, String strMatchday) {
    String url = BASE_URL + "eventsseason.php?id=" + selectedLeagueID + "&s=" + selectedSeason + "&round=" + strMatchday;

    JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.GET, url, null,
            response -> {
                try {
                    JSONArray eventsArray = response.getJSONArray("events");
                    for (int i = 0; i < eventsArray.length(); i++) {
                        JSONObject event = eventsArray.getJSONObject(i);

                        // Parse the fields
                        String idEvent = event.optString("idEvent");
                        String strEvent = event.optString("strEvent");
                        String strSeason = event.optString("strSeason");
                        String dateEvent = event.optString("dateEvent");
                        String strTime = event.optString("strTime");
                        String idHomeTeam = event.optString("idHomeTeam");
                        String idAwayTeam = event.optString("idAwayTeam");
                        String strHomeTeam = event.optString("strHomeTeam");
                        String strAwayTeam = event.optString("strAwayTeam");
                        String intHomeScore = event.optString("intHomeScore");
                        String intAwayScore = event.optString("intAwayScore");
                        String strVenue = event.optString("strVenue");
                        String strStatus = event.optString("strStatus");
                        String strPostponed = event.optString("strPostponed");
                        String strThumb = event.optString("strThumb");
                        String strVideo = event.optString("strVideo");

                        // Create a map for the event data
                        HashMap<String, Object> eventMap = new HashMap<>();
                        eventMap.put("idEvent", idEvent);
                        eventMap.put("strEvent", strEvent);
                        eventMap.put("strSeason", strSeason);
                        eventMap.put("dateEvent", dateEvent);
                        eventMap.put("strTime", strTime);
                        eventMap.put("idHomeTeam", idHomeTeam);
                        eventMap.put("idAwayTeam", idAwayTeam);
                        eventMap.put("strHomeTeam", strHomeTeam);
                        eventMap.put("strAwayTeam", strAwayTeam);
                        eventMap.put("intHomeScore", intHomeScore);
                        eventMap.put("intAwayScore", intAwayScore);
                        eventMap.put("strVenue", strVenue);
                        eventMap.put("strStatus", strStatus);
                        eventMap.put("strPostponed", strPostponed);
                        eventMap.put("strThumb", strThumb);
                        eventMap.put("strVideo", strVideo);
                        eventMap.put("order of arrival", i); // Add order of arrival

                        // Get selected league name and ID
                        String selectedLeague = (String) spinnerLeagues.getSelectedItem();
                        // String selectedLeagueID = leagueIDsList.get(spinnerLeagues.getSelectedItemPosition());
                        String compositeLeagueId = selectedLeague + ":" + selectedLeagueID;

                        // Store event in Firestore under the appropriate path
                        db.collection("events")
                                .document(compositeLeagueId)
                                .collection("seasons").document(selectedSeason)
                                .collection("matchdays").document(strMatchday)
                                .collection("matches")
                                .document(idEvent)
                                .set(eventMap)
                                .addOnSuccessListener(aVoid -> Log.d(TAG, "Event saved successfully"))
                                .addOnFailureListener(e -> Log.e(TAG, "Error saving event data", e));
                    }
                } catch (JSONException e) {
                    Log.e(TAG, "JSON parsing error in fetchEvents: ", e);
                }
            }, error -> {
        Log.e(TAG, "Network error in fetchEvents: ", error);
    }
    );

    Volley.newRequestQueue(this).add(jsonObjectRequest);
}

同时,修改btnFetchData按钮的点击事件调用fetchEvents方法,同时传递matchday参数,在这里,为了演示,我们暂时将 matchday 值设置为 "1",您可以根据实际需求调整为其他值或让用户输入:

 // Fetch data button action
        btnFetchData.setOnClickListener(v -> {
            String selectedSport = (String) spinnerSports.getSelectedItem();
            String selectedLeague = (String) spinnerLeagues.getSelectedItem();
            String selectedSeason = (String) spinnerSeasons.getSelectedItem();
            String selectedLeagueID = leagueIDsList.get(spinnerLeagues.getSelectedItemPosition());
            String strMatchday = "1"; // Here, matchday is hardcoded for demonstration purpose

            if (selectedSport != null && selectedLeague != null && selectedSeason != null) {
                fetchEvents(selectedLeagueID, selectedSeason, strMatchday); // Fetch data with matchday parameter