【问题标题】:How to add subcollection to a document in Firebase Cloud Firestore如何将子集合添加到 Firebase Cloud Firestore 中的文档
【发布时间】:2018-05-10 21:32:25
【问题描述】:

该文档没有任何关于如何将子集合添加到文档的示例。我知道如何将文档添加到集合以及如何将数据添加到文档,但是如何将集合(子集合)添加到文档?

不应该有这样的方法吗:

dbRef.document("example").addCollection("subCollection")

【问题讨论】:

    标签: java android ios firebase google-cloud-firestore


    【解决方案1】:

    2021 年 1 月 13 日编辑:

    根据关于array membership 的更新文档,现在可以使用whereArrayContains() 方法根据数组值过滤数据。一个简单的例子是:

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

    此查询返回每个城市文档,其中区域字段是包含 west_coast 的数组。如果数组有多个您查询的值的实例,则该文档仅包含在结果中一次。


    假设我们有一个聊天应用程序,其数据库结构类似于:

    要在文档中写入subCollection,请使用以下代码:

    DocumentReference messageRef = db
        .collection("rooms").document("roomA")
        .collection("messages").document("message1");
    

    如果你想创建messages 集合并调用addDocument() 1000 次肯定会很昂贵,但这就是 Firestore 的工作方式。如果需要,您可以切换到 Firebase 实时数据库,写入次数无关紧要。但是对于Firestore中的Supported Data Types,其实可以使用数组,因为是支持的。在Firebase Realtime database 中,您也可以使用array,但这是一种反模式。 Firebase 建议不要使用数组的众多原因之一是它使安全规则无法编写。

    Cloud Firestore 可以存储数组,它不支持查询数组成员或更新单个数组元素。但是,您仍然可以利用 Cloud Firestore 的其他功能对此类数据进行建模。 Here 是解释得很好的文档。

    您也不能创建一个包含 1000 条消息的子集合并将它们全部添加到数据库中,同时考虑一条记录。它将被视为对每条消息的一次写入操作。总共1000次操作。上图没有显示如何检索数据,它显示了一个数据库结构,其中你有这样的东西:

    collection -> document -> subCollection -> document
    

    【讨论】:

    • 例如,您想如何在 messages 集合中动态添加 1000 条消息(它们的 id 是自动生成的),然后在一个查询中将此集合添加到 roomA 中?我很确定创建messages 集合并调用addDocument() 1000 次会很昂贵(在所有意义上)。我正在寻找一种方法来创建这些文档并将它们分配给本地子集合,然后将子集合添加到文档中。我目前正在设置一个字典数组(或哈希图)并将该数组设置为文档的数据类型...
    • 但鉴于 Firestore 的强大功能,字典数组听起来并不是最佳解决方案。实际上,您上面的图片显示了如何从子集合中检索(如在文档中),但是文档中根本没有解释如何将子集合添加到文档中:(
    • 不能编写整个数组(集合)的事实有点疯狂。这是一个基本的需求,但我必须遍历所有内容才能将它们单独添加到集合中......让我想知道,首先使用 firestore 的优势是什么?
    • 请查看我的更新答案并查看此post 以获得更好的理解。你觉得我的回答对你有帮助吗?
    • 任何人请帮助使用网络查询在文档(房间A)中添加字段(“名称”)和集合(“消息”)。我不知道如何在文档中添加字段 + 集合
    【解决方案2】:

    这是一种变体,其中子集合在集合级别存储 ID 值,而不是在文档中,其中子集合是具有附加数据的字段。

    这对于连接 一对多 ID 映射很有用,而无需钻取其他文档:

    function fireAddStudentToClassroom(studentUserId, classroomId) {
    
        var db = firebase.firestore();
        var studentsClassroomRef =
            db.collection('student_class').doc(classroomId)
              .collection('students');
    
        studentsClassroomRef
            .doc(studentUserId)
            .set({})
            .then(function () {
                console.log('Document Added ');
            })
            .catch(function (error) {
                console.error('Error adding document: ', error);
            });
    }
    

    感谢@Alex's answer

    这个答案与这里的原始问题有点不同,它明确要求将集合添加到文档中。然而,在为这种情况寻找解决方案并且在文档或 SO 中没有找到任何提及之后,这篇文章似乎是分享发现的合理场所

    【讨论】:

      【解决方案3】:

      这是我的代码:

      firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).set(wordData)
        .then(function() {
          console.log("Collection added to Firestore!");
          var promises = [];
          promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('AudioSources').doc($scope.accentDialect).set(accentDialectObject));
          promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('FunFacts').doc($scope.longLanguage).set(funFactObject));
          promises.push(firebase.firestore().collection($scope.longLanguage + 'Words').doc($scope.word).collection('Translations').doc($scope.translationLongLanguage).set(translationObject));
          Promise.all(promises).then(function() {
            console.log("All subcollections were added!");
          })
          .catch(function(error){
            console.log("Error adding subcollections to Firestore: " + error);
          });
        })
        .catch(function(error){
          console.log("Error adding document to Firestore: " + error);
        });
      

      这将创建一个集合EnglishWords,其中包含一个文档of。文档of 包含三个子集合:AudioSources(以美国和英国口音记录的单词)、FunFactsTranslations。子集合Translations 有一个文档:SpanishSpanish 文档有三个键值对,告诉你'de'是'of'的西班牙语翻译。

      代码的第一行创建集合EnglishWords。我们等待用.then 解决的承诺,然后我们创建三个子集合。 Promise.all 告诉我们何时设置了所有三个子集合。

      恕我直言,当整个数组一起上传和下载时,我在 Firestore 中使用数组,也就是说,我不需要访问单个元素。例如,单词“of”的字母数组将是['o', 'f']。用户可以问:“我如何拼写‘of’?”用户不会问:“'of' 中的第二个字母是什么?”

      当我需要访问单个元素(也就是文档)时,我会使用集合。对于较旧的 Firebase 实时数据库,我必须下载数组,然后使用 forEach 遍历数组以获得我想要的元素。这是很多代码,并且由于数据结构和/或大型数组很深,我正在下载大量不需要的数据,并减慢了我的应用程序在大型数组上运行 forEach 循环的速度。 Firestore 将迭代器放在数据库的末端,这样我就可以请求单个元素,它只向我发送那个元素,从而节省了我的带宽并使我的应用程序运行得更快。如果您的计算机有宽带连接,这对于网络应用程序可能无关紧要,但对于数据连接较差且设备速度较慢的移动应用程序来说,这一点很重要。

      这是我的 Firestore 的两张图片:

      【讨论】:

        【解决方案4】:

        来自文档:

        您不需要“创建”或“删除”集合。在集合中创建第一个文档后,集合就存在了。如果您删除集合中的所有文档,则它不再存在。

        【讨论】:

          【解决方案5】:

          答案为时已晚,但这对我有用,

                  mFirebaseDatabaseReference?.collection("conversations")?.add(Conversation("User1"))
                      ?.addOnSuccessListener { documentReference ->
                          Log.d(TAG, "DocumentSnapshot written with ID: " + documentReference.id)
                          mFirebaseDatabaseReference?.collection("conversations")?.document(documentReference.id)?.collection("messages")?.add(Message(edtMessage?.text.toString()))
                      }?.addOnFailureListener { e ->
                          Log.w(TAG, "Error adding document", e)
                      }
          

          添加成功侦听器以添加文档并使用 firebase 生成的 ID 作为路径。 将此 ID 用于您要添加的新集合的完整路径。 IE。 - dbReference.collection('yourCollectionName').document(firebaseGeneratedID).collection('yourCollectionName').add(yourDocumentPOJO/Object)

          【讨论】:

            【解决方案6】:

            在这里我遇到了同样的问题并用@Thomas David Kehoe 的回答解决了

            db.collection("First collection Name").doc("Id of the document").collection("Nested collection Name").add({
                            //your data
                        }).then((data) => {
                            console.log(data.id);
                            console.log("Document has added")
                        }).catch((err) => {
                            console.log(err)
                        })
            

            【讨论】:

              【解决方案7】:

              好吧,鉴于 firebase/firestore 文档中的最新更新,我最近遇到了类似的问题。

              这是一个适合我的解决方案

                const sendMessage = async () => {
                  await setDoc(doc(db, COLLECTION_NAME, projectId, SUB_COLLECTION_NAME, nanoid()), {
                    text:'this is a sample text',
                    createdAt: serverTimestamp(),
                    name: currentUser?.firstName + ' ' + currentUser?.lastName,
                    photoUrl: currentUser?.photoUrl,
                    userId: currentUser?.id,
                  });
                }
              

              您可以在文档中找到类似的示例 https://firebase.google.com/docs/firestore/data-model#web-version-9_3

              chat room

              如果你想收听实时更新,你可以使用类似的方法如下

              const messagesRef = collection(db, COLLECTION_NAME, projectId, SUB_COLLECTION_NAME)
                    
              const liveUpdate = async () => {
                      const queryObj = query(messagesRef, orderBy("createdAt"), limit(25));
                      onSnapshot(queryObj, (querySnapshot) => {
                        const msgArr: any = [];
                        querySnapshot.forEach((doc) => {
                          msgArr.push({ id: doc.id, ...doc.data() })
                        });
                        console.log(msgArr);
                      });
                    }
              

              【讨论】:

                【解决方案8】:

                没有单独的方法可以将子集合添加到文档中。 您可以只调用收集方法本身。 如果集合存在,它将引用该集合,否则创建一个新集合。

                dbRef.document("example").collection("subCollection")
                

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2020-01-05
                  • 2018-07-30
                  • 1970-01-01
                  • 2021-05-09
                  • 1970-01-01
                  • 1970-01-01
                  • 2018-10-21
                  • 2019-06-04
                  相关资源
                  最近更新 更多