【问题标题】:Cloud Firestore - How to get relational data from two collections?Cloud Firestore - 如何从两个集合中获取关系数据?
【发布时间】:2019-03-12 18:33:14
【问题描述】:

我想在 Cloud Firestore 中定义这两个集合。部分示例数据如下所示:

播放列表:

  • 名称:“播放列表1”
  • songCount: //实时计算

歌曲:

  • 标题:“歌曲1”
  • playlistId: "playlist1"

  • 标题:“歌曲2”

  • playlistId: "playlist1"

  • 标题:“歌曲3”

  • playlistId:“playlist1”

此外,在我的 Android 应用中,我想显示所有播放列表和所有歌曲的单独列表。但是,在显示所有播放列表的列表时,我想根据“songCount”中的值显示每个播放列表的名称以及每个播放列表中包含的歌曲数量。

请告知我需要在 Cloud Firestore 中进行哪种查询才能实现此目标。是否有可用的JOIN 函数,或者我是否必须将 Songs 集合放在一个循环中并将具有 playlistId 的那些计数为“playlist1”,然后对要在播放列表列表中显示的所有播放列表重复它?我想要一个更智能的解决方案,但在互联网上找不到。

任何帮助都会有很大帮助。感谢您的宝贵时间。

【问题讨论】:

  • @LundinCast 我在发布之前检查了它,但它没有提供明确的答案,或者我可能无法正确回答。如果你已经理解了,请在这里解释一下。谢谢

标签: java android firebase google-cloud-firestore


【解决方案1】:

有加入功能吗?

很遗憾,Firestore 中没有 JOIN 查询。 Firestore 中的查询很浅:它们仅从运行查询的集合中获取项目。无法在单个查询中从顶级集合和其他集合或子集合中获取文档。 Firestore 不支持一次性跨不同集合进行查询。单个查询只能使用单个集合中文档的属性。所以我能想到的最简单的解决方案是使用类似这样的数据库结构:

Firestore-root
   |
   --- playlists (collection)
   |     |
   |     --- playListId (document) //The unique id of the play list
   |           |
   |           --- name: "playlist1"
   |
   --- songs (collection)
        |
        --- playListId (document) //The same as the above playListId
               |
               --- playListSongs
                     |
                     --- songId
                          |
                          --- title: "song1"

为了显示所有播放列表,只需将侦听器附加到 playlists 引用并获取所有 playlist 对象。如果您想获取与特定播放列表对应的所有歌曲,只需将侦听器附加到 songs\playListId\playListSongs 并获取所有 song 对象。

关于与播放列表对应的所有歌曲的数量,我建议您查看我在此 post 中的回答,我已在其中解释了您可以实现这一目标的方法。所以根据我回答的最后一部分,你的 Firebase 实时数据库结构应该是这样的:

Firebase-Realtime-Database-root
    |
    --- playlists
          |
          --- playListIdOne: numberOfSongs
          |
          --- playListIdTwo: numberOfSongs

编辑:

我不能说我完全理解它,尤其是因为第一个答案涉及 Firestore,第二个涉及 Firebase 实时数据库。

我为您提供了这个解决方案,因为如果您想在每次添加或删除歌曲时使用 Cloud Firestore 来计算和更新元素,Firestore 将针对每次写入/删除操作向您收费。 Firebase 实时数据库还有另一个 pricing plan,因此您无需为此付费。见Firestore pricing 请再读一遍直到最后,我的回答来自这个post

另外,我无法真正了解计算歌曲数量的程序。

这是您从 Firestore 获取歌曲数量并将其写入 Firebase 实时数据库的方法:

rootRef.collection("songs").document(playListId).collection("playListSongs")
.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
    @Override
    public void onComplete(@NonNull Task<QuerySnapshot> task) {
        if (task.isSuccessful()) {
            Log.d("TAG", task.getResult().size() + "");
            DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
            DatabaseReference playListIdRef = rootRef.child("playlists").child(playListId);
            playListIdRef.setValue(task.getResult().size());
            
        } else {
            Log.d(TAG, "Error getting documents: ", task.getException());
        }
    }
});

你可以这样阅读:

DatabaseReference rootRef = FirebaseDatabase.getInstance().getReference();
DatabaseReference playListIdRef = rootRef.child("playlists").child(playListId);
ValueEventListener valueEventListener = new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
            long playListIdOne = dataSnapshot.getValue(String.Long);
            Log.d(TAG, "playListIdOne: " + playListIdOne);
    }

    @Override
    public void onCancelled(@NonNull DatabaseError databaseError) {
        Log.d(TAG, databaseError.getMessage());
    }
};
playListIdRef.addListenerForSingleValueEvent(valueEventListener);

其次,根据您建议的结构,我如何获得所有播放列表中所有歌曲的列表?

在这种情况下,您应该创建另一个集合,名为 allSongs。数据库中的附加集合应如下所示:

Firestore-root
   |
   --- allSongs
         |
         --- songId
              |
              --- //song details

这种做法称为denormalization,是 Firebase 的常见做法。为了更好地理解,我建议您观看此视频,Denormalization is normal with the Firebase Database。它适用于 Firebase 实时数据库,但同样的规则适用于 Cloud Firestore。

此外,当您复制数据时,您需要记住一件事。与添加数据的方式相同,您需要对其进行维护。换句话说,如果你想更新/删除一个项目,你需要在它存在的每个地方都这样做。

请记住,同一首歌曲可以在多个播放列表中找到。

没关系,因为每首歌都有不同的id。

【讨论】:

  • 感谢您提供如此详细的答案。我不能说我已经完全理解它,特别是因为第一个答案涉及 FireStore,第二个涉及 Firebase 实时数据库。另外,我无法真正了解计算歌曲数量的程序。其次,根据您建议的结构,我将如何获得所有播放列表中所有歌曲的列表,记住一首相同的歌曲可以在多个播放列表中找到?再次感谢您抽出宝贵时间。
  • 不应该是rootRef.collection("songs").document(playListId).collection("playListSongs").get() 吗?
  • 是的,你是对的。我的错,对此感到抱歉。刚刚更新了我的答案。现在可以了吗?
  • 是的。您的回答消除了一些困惑,但也造成了一些困惑。那只是因为我对 Firebase 完全陌生。我的实际目标是别的东西。在互联网上大量阅读并观看了许多视频之后,我认为 Firebase/Firestore 可能会帮助我实现它....现在我不这么认为了。我相信现在是我退后一步,再次专注于我的实际目标的时候了。我将把它作为一个关于 SO 的新问题发布,并要求所有专家,尤其是你,相应地指导我。您的回答可能会帮助我在不诉诸 Firebase 的情况下实现它。
  • 我去看看,如果我知道答案,我会写给你的。
猜你喜欢
  • 2019-06-05
  • 2022-11-06
  • 2019-12-24
  • 2018-11-07
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
  • 2020-11-26
相关资源
最近更新 更多