天道酬勤,学无止境

Is there a way to batch read firebase documents

I am making a mobile app using flutter with firebase as my backend.

I have a collection of user document that stores user information. one of the fields is an array of references (reference documents in another collection) which I want to use in an operation like batch that in that would then allow be to read all the documents.

I know batch only allows writes to the database, My second option would be Transaction, which requires writes after reads which I am trying to avoid.

Is there a way to read multiple documents in one operation without having to use Transaction?

评论

Firestore doesn't offer a formal batch read API. As Frank mentions in his comment, there is a way to use IN to fetch multiple documents from a single collection using their IDs. However, all of the documents must be in the same collection, and you can't exceed 10 documents per query. You might as well just get() for each document individually, as the IN query has limitations, and isn't guaranteed to execute any faster than the individual gets. Neither solution is guaranteed to be "consistent", so any one of the documents fetched could be "more fresh" than the others at any given moment in time.

Firestore has a REST API that allows you to do batch GETs with document paths that may be what you need.

See https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/batchGet

If you know the document IDs and the collection paths of the documents needed to be fetched, you could always use the getAll() method which is exposed in the firebase Admin SDK (at least for Node.js environments).

Then, for example, you could write an HTTPS Callable Function that would accept a list of absolute document paths and perform a "batch get" operation on them using the getAll() method.

e.g.

// Import firebase functionality
const functions = require('firebase-functions');
const admin = require('firebase-admin');

// Configure firebase app
admin.initializeApp(functions.config().firebase);

// HTTPS callable function
exports.getDocs = functions.https.onCall((data, context) => {

    const docPathList = data.list; // e.g. ["users/Jkd94kdmdks", "users/8nkdjsld", etc...]
    const firestore = admin.firestore();

    var docList = [];

    for (var i = 0; i <= docPathList.length - 1; i++) {

        const docPath = docPathList[i];
        const doc = firestore.doc(docPath);
        docList.push(doc);
    }

    // Get all
    return firestore.getAll(...docList)
        .then(results => {
            return { data : results.map(doc => doc.data()) };
        })
        .catch(err => {
            return { error : err };
        })
});

Not sure what the limit (if any) is for the number of documents you can fetch using getAll(), but I do know my application is able to fetch at least 50 documents per call successfully using this method.

受限制的 HTML

  • 允许的HTML标签:<a href hreflang> <em> <strong> <cite> <blockquote cite> <code> <ul type> <ol start type> <li> <dl> <dt> <dd> <h2 id> <h3 id> <h4 id> <h5 id> <h6 id>
  • 自动断行和分段。
  • 网页和电子邮件地址自动转换为链接。

相关推荐
  • 将 Firebase Firestore 和 Firebase Storage 调用组合成一个批处理?(Couple Firebase Firestore and Firebase Storage calls together into a batch?)
    问题 我正在寻找有关 Firebase Storage 和 Firebase Firestore 的组合/批量调用的最佳实践。 例如:我需要从我的 Firestore 中删除一个与 Firebase Storage 中的图像相关的文档。 是否有可能以这样的方式执行此操作:当其中一个操作失败时,整个事务将被还原? 回答1 没有真正的atomic/transactional方法可以做到这一点,但是您可以使用云函数来可靠地实现它。 您可以删除一个文档,并使用 onDelete 触发器删除存储中的实际文件。 因此,当您无法删除该文档时,该文件不会发生任何变化。 如果您成功删除文档,则会触发云功能删除图像。 回答2 Firebase 产品均不支持此类跨产品事务更新。 您必须在更新期间嵌套调用,并使用可以在读取期间处理意外数据结构的代码。 另见: 如何在 Firebase 中编写非规范化数据以获取一般更新方法(此处并非全部适用)。 Firebase 处理有关存储和实时数据库之间跨产品一致性的突然丢失
  • Cloud Firestore:强制执行唯一的用户名(Cloud Firestore: Enforcing Unique User Names)
    问题 问题 我已经多次(在Firebase实时数据库中)看到过这个问题,但是我没有看到有说服力的答案。 问题陈述非常简单: (经过身份验证的)用户如何选择尚未使用的用户名? 首先,原因:用户进行身份验证后,他们具有唯一的用户ID。 但是,许多网络应用程序都允许用户选择“显示名称”(用户希望在网站上显示的方式),以保护用户的个人数据(例如真实姓名)。 用户集合 给定如下数据结构,可以为每个用户存储用户名和其他数据: /users (collection) /{uid} (document) - name: "<the username>" - foo: "<other data>" 但是,没有什么可以阻止另一个用户(具有不同的{uid} )在其记录中存储相同的name 。 据我所知,没有“安全规则”可让我们检查该name是否已被另一个用户使用。 注意:可以进行客户端检查,但是不安全,因为恶意客户端可能会忽略该检查。 反向映射 流行的解决方案是使用反向映射创建集合: /usernames (collection) /{name} (document) - uid: "<the auth {uid} field>" 给定此反向映射,可以编写安全规则来强制用户名尚未使用: match /users/{userId} { allow read: if true; allow create
  • 如何在 Firestore 中进行批量更新(How to do a bulk update in Firestore)
    问题 我正在使用 Cloud Firestore 并有一系列文档。 对于集合中的每个文档,我想更新其中一个字段。 使用事务来执行更新将是低效的,因为我在更新数据时不需要读取任何数据。 批量更新似乎是正确的方向,但是文档不包括一次更新多个文档的示例。 请参阅此处:批量写入 回答1 如果您使用过 Firebase 数据库,则不可能以原子方式写入完全单独的位置,这就是您必须使用批量写入的原因,这意味着要么所有操作都成功,要么都不应用。 关于 Firestore,所有操作现在都以原子方式处理。 但是,您可以将多个写入操作作为包含 set()、update() 或 delete() 操作的任意组合的单个批处理来执行。 一批写入以原子方式完成,可以写入多个文档。 这是一个关于写入、更新和删除操作的批处理操作的简单示例。 WriteBatch batch = db.batch(); DocumentReference johnRef = db.collection("users").document("John"); batch.set(johnRef, new User()); DocumentReference maryRef = db.collection("users").document("Mary"); batch.update(maryRef, "Anna", 20); /
  • 如何从应用程序远程强制注销 firebase auth 用户(How to force logout firebase auth user from app remotely)
    问题 我有一个项目,它使用 firebase auth 和 firebaseUI 来验证用户。 我已启用 Google、Facebook 和电子邮件提供商。 我需要的是远程注销或禁用某些用户。 我希望用户在这样做时从应用程序注销。 我尝试在 firebase 控制台中禁用用户,并使用 firebase admin SDK (https://firebase.google.com/docs/auth/admin/manage-sessions) 来撤销刷新令牌。 我等了 2 多天,仍然注意到用户已登录并且可以访问 firestore 数据。 我也经历过并尝试过 Firebase 在删除后仍然检索 authData 谁能指出我做错了什么? 回答1 您也无法远程强制用户注销。 任何注销都必须在用户登录的设备上进行。 一旦铸造,就无法撤销访问令牌。 这意味着即使您禁用用户的帐户,他们仍可能继续拥有长达一个小时的访问权限。 如果这太长,诀窍(正如我对您链接的问题的回答中所提到的)是在您的数据库(或其他地方)中维护一个被阻止用户的列表,然后在您的安全规则(或其他授权层)中进行检查)。 例如,在实时数据库中,您可以创建一个被阻止用户的 UID 列表: banned_uids: { "uid1": true "uid2": true } 然后在您的安全规则中检查: ".read": "auth
  • 删除Firestore集合中的所有文档(Deleting all documents in Firestore collection)
    问题 我正在寻找清除整个收藏夹的方法。 我看到有一个批处理更新选项,但这需要我知道集合中的所有文档ID。 我正在寻找一种简单地删除集合中每个文档的方法。 谢谢! 编辑:下面的答案是正确的,我使用了以下内容: func delete(collection: CollectionReference, batchSize: Int = 100) { // Limit query to avoid out-of-memory errors on large collections. // When deleting a collection guaranteed to fit in memory, batching can be avoided entirely. collection.limit(to: batchSize).getDocuments { (docset, error) in // An error occurred. let docset = docset let batch = collection.firestore.batch() docset?.documents.forEach { batch.deleteDocument($0.reference) } batch.commit {_ in self.delete(collection: collection
  • 如何在Cloud Firestore安全规则中实施写入速率限制?(How do I implement a write rate limit in Cloud Firestore security rules?)
    问题 我有一个使用Firebase SDK从应用程序内部直接与Cloud Firestore对话的应用程序。 我的代码确保仅在合理的时间间隔内写入数据。 但是恶意用户可能会从我的应用程序中获取配置数据,并使用它向我的数据库中写入无休止的数据流。 我如何确保用户每隔几秒钟只能写一次发言,而不必编写任何服务器端代码。 回答1 对数据库的每次读取或写入操作都将根据您为项目配置的安全规则在Google的服务器上进行验证。 这些规则只能由项目的协作者设置,但适用于访问项目中数据库的所有客户端代码。 这意味着您可以在这些安全规则中强制执行此条件,即使恶意用户也无法绕过它们,因为它们无权访问您的项目。 假设我们有一个users集合,并且那里的每个文档都有一个带有用户UID的ID。 这些安全规则确保用户只能写自己的文档,并且每5秒只能写一次: match /users/{document=**} { allow create: if isMine() && hasTimestamp(); allow update: if isMine() && hasTimestamp() && isCalm(); function isMine() { return request.resource.id == request.auth.uid; } function hasTimestamp() {
  • 您如何避免使用 Firebase 云功能可能出现的竞争条件?(How do you avoid a possible race condition with firebase cloud functions?)
    问题 我有一个由 Firestore 数据库写入触发的云功能。 它执行异步操作(从某些 3rd 方 API 获取数据)可能需要很长时间,也可能不需要。 完成后,它将结果写入“搜索结果”字段。 可能存在竞争条件,即较新触发器的结果被较晚完成的较旧操作覆盖。 在 Firebase 云函数和 Firestore 的上下文中,我应该如何解决这个问题? 回答1 一般来说,这里有两种方法: 确保您的操作是幂等的确保您的操作检测到冲突更新并重试 确保您的操作是幂等的 这通常是最可扩展和架构最简单的。 当您对相同的输入执行相同的幂等操作时,它具有相同的结果。 这意味着多次执行操作并不重要,因为结果将是相同的。 一个很好的例子是关于数组和集合的 Firestore 文档。 想象一下,您正在使用类别标记博客文章。 一个简单的模型是: { title: "My great post", categories: [ "technology", "opinion", "cats" ] } 但是现在想象一下,两个用户几乎同时将同一个帖子标记为关于猫。 你可能会得到 { title: "My great post", categories: [ "technology", "opinion", "cats", "cats" ] } 这显然不是你想要的。 但由于数据结构允许,这可能会发生。
  • Cloud Functions:如何将 Firestore 集合复制到新文档?(Cloud Functions: How to copy Firestore Collection to a new document?)
    问题 我想在使用 Cloud Functions 的事件发生时在 Firestore 中制作集合的副本 我已经有了这个代码,它遍历集合并复制每个文档 const firestore = admin.firestore() firestore.collection("products").get().then(query => { query.forEach(function(doc) { var promise = firestore.collection(uid).doc(doc.data().barcode).set(doc.data()); }); }); 有更短的版本吗? 一次只复制整个集合? 回答1 目前,没有。 使用 Cloud Functions 循环遍历每个文档,然后将一个新文档设置为具有指定数据的不同集合是执行此操作的唯一方法。 也许这将是一个很好的功能请求。 我们在谈论多少文件? 对于像 10,000 这样的东西,它应该只需要几分钟,顶部。 回答2 我为此编写了一个小的 nodejs 片段。 const firebaseAdmin = require('firebase-admin'); const serviceAccount = '../../firebase-service-account-key.json'; const firebaseUrl =
  • Batch write to firebase cloud firestore
    I want to create a new collection and add thousands of documents sized ~ 1-2K to it. I already have data in json so I thought this would be easy. I understand that batch can have 500 writes at a time so to break it into chunks of 500 I wrote the following code. Though for testing purpose I am running it with chunks of 20 and my test json has 72 objects. But I keep getting the following error node_modules\@google-cloud\firestore\src\write-batch.js:148 throw new Error('Cannot modify a WriteBatch that has been committed.'); ^ Error: Cannot modify a WriteBatch that has been committed. My code is
  • 如何更新单个 Firebase Firestore 文档(How to update a single firebase firestore document)
    问题 身份验证后,我试图在 /users/ 查找用户文档,然后我想用来自 auth 对象的数据以及一些自定义用户属性更新文档。 但是我收到一个错误,提示更新方法不存在。 有没有办法更新单个文档? 所有 firestore doc 示例都假定您拥有实际的 doc id,并且它们没有任何使用 where 子句查询的示例。 firebase.firestore().collection("users").where("uid", "==", payload.uid) .get() .then(function(querySnapshot) { querySnapshot.forEach(function(doc) { console.log(doc.id, " => ", doc.data()); doc.update({foo: "bar"}) }); }) 回答1 您可以精确地执行以下操作(https://firebase.google.com/docs/reference/js/firebase.firestore.DocumentSnapshot#ref): var db = firebase.firestore(); db.collection("users").doc(doc.id).update({foo: "bar"}); 回答2 检查用户是否已经在那里然后简单地
  • 批量写入 Firebase Cloud Firestore(Batch write to firebase cloud firestore)
    问题 我想创建一个新集合并向其中添加数千个大小约为 1-2K 的文档。 我已经在 json 中有数据,所以我认为这很容易。 我知道批处理一次可以有 500 次写入,因此为了将其分成 500 次,我编写了以下代码。 尽管出于测试目的,我使用 20 个块运行它,而我的测试 json 有 72 个对象。 但我不断收到以下错误 node_modules\@google-cloud\firestore\src\write-batch.js:148 throw new Error('Cannot modify a WriteBatch that has been committed.'); ^ Error: Cannot modify a WriteBatch that has been committed. 我的代码如下 var dataObj = JSON.parse(fs.readFileSync('./bigt.json')) var tmpdd = dataObj.slice(0, 72) var batch = db.batch(); console.log(tmpdd.length) let tc = tmpdd.length let lc = 0 let upperLimit = 20, dd = null while(lc<=tc){ dd = tmpdd.slice(lc
  • Firestore唯一索引或唯一约束?(Firestore unique index or unique constraint?)
    问题 在Firestore中是否可以定义具有唯一约束的索引? 如果不是,如何在文档字段上强制唯一性(不使用文档ID)? 回答1 是的,可以结合使用两个集合,Firestore规则和批处理写入来实现。 https://cloud.google.com/firestore/docs/manage-data/transactions#batched-writes 一个简单的想法是,使用批处理写入,将文档写入“数据”集合,并同时写入单独的“索引”集合,在其中您索引要唯一的字段的值。 使用Firestore规则,然后可以确保只有在索引集合中还存在document字段的值的情况下,才可以向“数据”集合写入文档,反之亦然,只有在有value的情况下,才能将索引集合写入索引中的匹配数据集合中的内容。 例子 假设我们有一个User集合,并且我们要确保username字段是唯一的。 我们的User集合将仅包含username /User/{id} { username: String } 我们的Index集合将在路径中包含用户名,并在value属性中包含所索引的User的ID。 /Index/User/username/{username} { value: User.id } 要创建我们的User我们使用批处理写入来同时创建User文档和Index文档。 const firebaseApp =
  • 离线时在 Firestore 中添加/更新数据的正确方法是什么?(What's the proper way to add/update data in Firestore when offline?)
    问题 当我的应用程序离线并且我正在添加或更新文档时,内存会增加。 此外,显示文档列表需要更长的时间来加载。 如果我在设备在线时运行相同的代码,内存将保持一致,以及具有文档列表的活动的速度。 我目前正在做如下保存: collectionRef.document(id).set(obj, SetOptions.merge()); 或者批处理几个记录: batch.set(docRef1, obj1); batch.set(docRef2, obj2); batch.commit(); 我有 onComplete 的听众,但在这个问题的公认答案中,似乎表明在大多数情况下听众是不必要的,并且当您离线时,无论如何您都无法等待它完成。 在另一个问题中,他们在代码中指出正确进行在线和离线保存需要“快照”:Firestore 与 Firebase 的离线问题。 但我找不到其他任何地方表明这是否会有所作为。 我认为快照是当您希望收到更改通知时附加到文档或查询的东西,并且附加这样的侦听器如果不删除它会导致内存泄漏。 所有这一切的另一部分是这种缓慢可能如何影响数据完整性。 当我在 Android Studio 的分析器中观看时,我看到 FirestoreWorker 可以达到一个持续工作的程度,即使我没有在应用程序中做任何事情。 我说的不只是几秒钟,更像是一分钟。 当我可以找到离线时
  • 如何批量删除 Firebase 匿名用户(How to bulk delete Firebase anonymous users)
    问题 由于我可能滥用匿名身份验证(请参阅如何防止 Firebase 匿名用户令牌过期),我的应用中有很多我实际上并不想要的匿名用户。 我看不到批量删除这些用户的任何方法。 我必须一一手动完成吗? 无论如何,是否可以使用 API 访问用户帐户并为当前用户以外的用户操作它们? 回答1 Firebase 控制台无法批量删除用户。 没有用于批量删除用户的 API。 但是有管理 API 允许您删除用户帐户。 请参阅 https://firebase.google.com/docs/auth/admin/manage-users#delete_a_user 回答2 此代码示例使用适用于 Node.js 的 Firebase Admin SDK,并将删除任何没有providerData的用户,这意味着该用户是匿名的: function deleteAnonymousUsers(nextPageToken) { adminApp .auth() .listUsers(20, nextPageToken) .then(function(listUsersResult) { listUsersResult.users.forEach(function(userRecord) { if (userRecord.providerData.length === 0) { //this user is
  • 在Firestore中删除包含所有子集合和嵌套子集合的文档(Delete a Document with all Subcollections and Nested Subcollections in Firestore)
    问题 如何删除带有所有集合和嵌套子集合的文档? (在功能环境内) 在RTDB中,您可以ref.child('../someNode).setValue(null)来完成所需的行为。 我可以想到两种方法来实现所需的删除行为,这两种方法都具有严重的弊端。 创建一个“超级”功能,该功能将抓取每个文档并将其批量删除。 该函数将很复杂,难以更改,并且可能需要很长的执行时间。 为每种Document类型添加“ onDelete”触发器,并使其删除任何直接子集合。 您将在根文档上调用delete,并且删除调用将沿“树”传播。 由于功能执行的巨大负担,它速度慢,伸缩性差且成本高昂。 想象一下,您将必须删除“组”及其所有子级。 #1会造成混乱,而#2会变得昂贵(每个文档1个函数调用) groups > GROUP > projects > PROJECT > files > FILE > assets > ASSET > urls > URL > members > MEMBER > questions > QUESTION > answers > ANSWER > replies > REPLY > comments > COMMENT > resources > RESOURCE > submissions > SUBMISSION > requests > REQUEST
  • 将 Firebase 实时数据库迁移到 Firestore(Migrate Firebase Realtime Database to Firestore)
    问题 我正在寻找将使用 firebase 实时数据库的应用程序数据库迁移到新 Cloud Firestore 数据库的最佳方法。 我对我正在从事的项目充满信心,我不需要进行任何数据架构更改,所以我几乎只是尝试 1-1 映射它。 Firebase 在他们的网站上建议只编写一个脚本来执行此操作,但我不确定最好的方法。 有没有人已经制作了一个脚本来完成这个? 回答1 我写了一个小节点脚本,它以一种快速而肮脏的方式迁移东西,它工作得很好。 如果有人感兴趣,它在下面。 注意:仅当实时数据库中的数据模型完全平坦且没有太多嵌套数据时才应使用此方法,并且您打算在 Firestore 中也保持数据平坦 要运行此脚本,只需创建一个名为 index.js 的节点文件,并将其与您的服务帐户文件和来自实时数据库导出的原始 json 文件一起放入一个目录中,然后从命令行运行以下命令。 $ node index.js 下面的脚本实现。 const admin = require('firebase-admin'); var serviceAccount = require("./config.json"); var database = require("./database.json"); var async = require ('async'); admin.initializeApp({
  • Couple Firebase Firestore and Firebase Storage calls together into a batch?
    I'm looking for a best practice on combined/batch calls for Firebase Storage and Firebase Firestore. For example: I need to delete a document from my Firestore which is related to an image in Firebase Storage. Is there a possibility to do this in such a way that when one of the actions fails, the whole transaction is being reverted?
  • 如何从 NodeJS Admin SDK 中的 Firebase 身份验证中删除上次登录超过特定时间的匿名用户?(how to delete anonymous users that last signed in more than certain time from Firebase Authentication in NodeJS Admin SDK?)
    问题 来自 Firebase 身份验证,我们有这样的表格,提供者可以是电子邮件、谷歌、脸书或匿名 我需要删除上次登录是在六个月前的所有匿名帐户。 我需要查询那些匿名帐户,然后将它们全部删除。 但我真的不知道如何使用 Node JS 管理 SDK 查询上次登录超过六个月前的所有匿名帐户。 是否可以? 怎么做? 因为此处的文档中存在来自 firebase(1 亿个匿名帐户)的限制。 我可能没有达到这个限制,但我认为如果我可以通过在云功能中使用云调度程序创建一个 cron 作业来清理未使用的匿名帐户会更好 回答1 我想我找到了解决方案,建议您先阅读此 Firebase 官方文档,了解如何从身份验证中获取所有用户,您需要阅读那里的说明。 没有像查询这样的东西来获取我们需要的数据,至少现在是这样 我将使用 Typescript 和 async/await 而不是 then/catch 和 Javascript。 但是如果你使用javascript,那么你只需要稍微修改一下函数参数 import * as moment from "moment"; const auth = admin.auth(); export const deleteUnusedAnonymousUsers = async function(nextPageToken?: string) { // this is a
  • Google Firestore - 如何在一次往返中通过多个 ID 获取多个文档?(Google Firestore - How to get several documents by multiple ids in one round-trip?)
    问题 我想知道是否有可能通过一个 id 列表在一次往返(网络调用)到 Firestore 数据库中获取多个文档。 回答1 如果您在 Node 中: https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L978 /** * Retrieves multiple documents from Firestore. * * @param {...DocumentReference} documents - The document references * to receive. * @returns {Promise<Array.<DocumentSnapshot>>} A Promise that * contains an array with the resulting document snapshots. * * @example * let documentRef1 = firestore.doc('col/doc1'); * let documentRef2 = firestore.doc('col/doc2'); * * firestore.getAll(documentRef1, documentRef2).then(docs => { * console.log(
  • 如何删除firestore中具有不同ID的多个文档? [复制](How to delete multiple documents that have different ids in firestore? [duplicate])
    问题 这个问题在这里已经有了答案: 如何从 Firestore 中删除集合或子集合? (1 个回答) 2年前关闭。 我有多个具有不同 ID 的文档,我需要实现一些方法来将它们全部删除,我进行了搜索,所以我想我应该采用的方法是使用批处理。 所以我的数据库如下图所示 所以我能够在这样的数组列表中获取我的文档的 id.. [0Y5rfMK3duHBUTN9XsO5,2Q70mSjNxkAoUMDAJ8rz,等等...] 和我的代码: WriteBatch batch = db.batch(); DocumentReference myRef = db.collection("Collection").document(String.valueOf(idsList)); batch.delete(myRef); batch.commit(); 但这不起作用,所以如果有一点遗漏,或者如果有任何其他方法可以执行它,将不胜感激写下来。 回答1 您必须迭代您的列表并分别为每个列表创建一个 DocumentReference。 DocumentReference 只能引用单个文档,不能引用文档列表: WriteBatch batch = db.batch(); for (String id : idsList) { DocumentReference ref = db.collection(