Cloud Firestore - 如何从两个集合中获取关系数据? [英] Cloud Firestore - How to get relational data from two collections?

查看:20
本文介绍了Cloud Firestore - 如何从两个集合中获取关系数据?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我想在 Cloud Firestore 中定义这两个集合.一些示例数据如下所示:

播放列表:

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

歌曲:

  • 标题:歌曲1"
  • 播放列表 ID:播放列表 1"

  • 标题:song2"

  • 播放列表 ID:播放列表 1"

  • 标题:song3"

  • 播放列表 ID:播放列表 1"

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

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

任何帮助都会有很大帮助.感谢您抽出宝贵时间.

解决方案

有加入功能吗?

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

Firestore-root|--- 播放列表(合集)|||--- playListId (document)//播放列表的唯一id|||---名称:播放列表1"|---歌曲(合集)|--- playListId (document)//与上面的playListId相同|--- 播放列表歌曲|--- 歌曲编号|--- 标题:song1"

要显示所有播放列表,只需将侦听器附加到 playlists 引用并获取所有 playlist 对象.如果您想获取与特定播放列表对应的所有歌曲,只需将侦听器附加到 songsplayListIdplayListSongs 并获取所有 song 对象.

关于与播放列表对应的所有歌曲的数量,我建议您从这个post,我已经解释了您可以实现的目标.因此,根据我回答的最后一部分,您的 Firebase 实时数据库结构应如下所示:

Firebase-Realtime-Database-root|--- 播放列表|--- playListIdOne: numberOfSongs|--- playListIdTwo: numberOfSongs

<块引用>

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

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

<块引用>

另外,我真的无法得到计算歌曲数量的程序.

您可以通过以下方式从 Firestore 获取歌曲数量并将其写入 Firebase 实时数据库:

rootRef.collection("songs").document(playListId).collection("playListSongs").get().addOnCompleteListener(new OnCompleteListener() {@覆盖public void onComplete(@NonNull Task 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());} 别的 {Log.d(TAG, "获取文档时出错:", task.getException());}}});

这就是你可以阅读的方式:

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

<块引用>

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

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

Firestore-root|- - 所有歌曲|--- 歌曲编号|---//歌曲详情

这种做法称为反规范化,是 Firebase 的常见做法.为了更好地理解,我建议您观看此视频,Firebase 数据库的非规范化是正常的.它适用于 Firebase 实时数据库,但相同的规则适用于 Cloud Firestore.

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

<块引用>

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

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

I want to define these two collections in Cloud Firestore. Some sample data has been shown below:

Playlists:

  • name: "playlist1"
  • songCount: //To be calculated on real time

Songs:

  • title: "song1"
  • playlistId: "playlist1"

  • title: "song2"

  • playlistId: "playlist1"

  • title: "song3"

  • playlistId: "playlist1"

Further, in my Android app, I want to show separate lists of all playlists and all songs. However, while displaying the list of all playlists, I want to show the name of each playlist alongwith the number of songs contained in each, based on the value in "songCount".

Please advise what sort of query I need to make in Cloud Firestore to achieve this objective. Is there a JOIN function available or would I have to put the Songs collection in a loop and count the ones having playlistId as "playlist1", and then repeat it for all the playlists that are to be presented in the list of playlists? I want to have a smarter solution but couldn't find one on the internet.

Any help would be a great help. Thanks for your time.

解决方案

Is there a Join function available?

Unfortunately, there is no JOIN query in Firestore. Queries in Firestore are shallow: they only get items from the collection that the query is run against. There is no way to get documents from a top-level collection and other collections or sub-collections in a single query. Firestore doesn't support queries across different collections in one go. A single query may only use properties of documents in a single collection. So the most simple solution I can think of would be to use a database structure that looks similar to this:

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"

In order to display all playlists, just attach a listener to the playlists reference and get all playlist objects. If you want to get all songs that correspond to a particular playlist, just attach a listener to songsplayListIdplayListSongs and get all song objects.

Regarding the count of all songs that correspond to a playlist, I recommend you see my answer from this post, where I have explained what you can achieve this. So according to the last part of my answer, your Firebase Realtime Database structure should look like this:

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

Edit:

I can't say I've understood it fully especially because the first answer involves Firestore and the second involves Firebase Realtime Database.

I gave you this solution because if you want to use Cloud Firestore to count and update elements every time a song is added or deleted, you'll be charged by Firestore for every write/delete operation. Firebase Realtime Database has another pricing plan, so you'll not be charged for that. See Firestore pricing Please read again till the end, my answer from this post.

Also, I couldn't really get the procedure for calculating the count of songs.

This is how you can get the number of songs from Firestore and write it to the Firebase Realtime Database:

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

And this is how you can read:

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

Secondly, as per your suggested structure, how would I get a list of all songs across all playlists?

In this case, you should create another collection, named allSongs. The additional collection in your database should look like this:

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

This practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database. It is for Firebase Realtime Database but same rules apply to Cloud Firestore.

Also, when you are duplicating data, there is one thing that you need to keep in mind. In the same way you are adding data, you need to maintain it. In other words, if you want to update/delete an item, you need to do it in every place that it exists.

Keeping in mind that one same song can be found in more than one playlists.

It doesn't matter because each song has a different id.

这篇关于Cloud Firestore - 如何从两个集合中获取关系数据?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆