如何将子集合添加到 Firebase Cloud Firestore 中的文档
Posted
技术标签:
【中文标题】如何将子集合添加到 Firebase Cloud Firestore 中的文档【英文标题】:How to add subcollection to a document in Firebase Cloud Firestore 【发布时间】:2018-05-10 21:32:25 【问题描述】:该文档没有任何关于如何将子集合添加到文档的示例。我知道如何将文档添加到集合以及如何将数据添加到文档,但是如何将集合(子集合)添加到文档?
不应该有这样的方法吗:
dbRef.document("example").addCollection("subCollection")
【问题讨论】:
【参考方案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 fireAddStudentToClas-s-room(studentUserId, clas-s-roomId)
var db = firebase.firestore();
var studentsClas-s-roomRef =
db.collection('student_class').doc(clas-s-roomId)
.collection('students');
studentsClas-s-roomRef
.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
(以美国和英国口音记录的单词)、FunFacts
和Translations
。子集合Translations
有一个文档:Spanish
。 Spanish
文档有三个键值对,告诉你'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")
【讨论】:
以上是关于如何将子集合添加到 Firebase Cloud Firestore 中的文档的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Firestore 中获取生成的文档 ID,然后将子集合添加到其中?
如何将 CSV 或 JSON 导入到 Firebase Cloud Firestore
从Firebase的Cloud Firestore删除文档是否会删除该文档中的所有子集合?
如何在 Firebase + Firestore + Flutter 中使用 StreamBuilder 将所有子集合数据获取到 Widget