Google Firestore - 如何在一次往返中通过多个ID获取文档?

时间:2017-10-13 02:18:43

标签: firebase google-cloud-firestore

我想知道是否可以通过往返Firestore的往返(网络电话)中的ID列表获取多个文档。

13 个答案:

答案 0 :(得分:39)

如果你在Node:

https://github.com/googleapis/nodejs-firestore/blob/master/dev/src/index.ts#L701

/**
* 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(`First document: ${JSON.stringify(docs[0])}`);
*   console.log(`Second document: ${JSON.stringify(docs[1])}`);
* });
*/

答案 1 :(得分:9)

不,现在无法使用Cloud Firestore SDK批量处理多个读取请求,因此无法保证您可以一次读取所有数据。

然而正如Frank van Puffelen在上面的评论中所说,这并不意味着获取3个文档的速度是获取一个文档的3倍。在得出结论之前,最好先进行自己的测量。

答案 2 :(得分:6)

你可以使用这样的函数:

function getById (path, id) {
  return firestore.getAll(
    [].concat(ids).map(id => firestore.doc(`${path}/${id}`)
  )
}

可以使用单个ID调用它:

getById('collection', 'some_id')

或ID数组:

getById('collection', ['some_id', 'some_other_id'])

答案 3 :(得分:6)

他们刚刚宣布了此功能https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html

现在您可以使用类似的查询,但是请注意输入大小不能大于10。

userCollection.where('uid', 'in', ["1231","222","2131"])

答案 4 :(得分:6)

如果您使用的是颤振,则可以执行以下操作:

Firestore.instance.collection('your collection name').where(FieldPath.documentId, whereIn:[list containing multiple document IDs]).getDocuments();

这将返回包含List<DocumentSnapshot>的Future,您可以根据需要对其进行迭代。

答案 5 :(得分:4)

当然,最好的方法是在云功能中实现Firestore的实际查询?那么从客户端到Firebase只会有一次往返电话,这似乎是你所要求的。

你真的希望保留所有的数据访问逻辑,就像这个服务器端一样。

在内部可能会有相同数量的对Firebase本身的调用,但它们都会跨越Google的超快速互连,而不是外部网络,再加上Frank van Puffelen所解释的流水线,你应该得到这种方法的出色表现。

答案 6 :(得分:2)

在实践中,您将像这样使用firestore.getAll

async getUsers({userIds}) {
    const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
    const users = await this.firestore.getAll(...refs)
    console.log(users.map(doc => doc.data()))
}

或使用promise语法

getUsers({userIds}) {
    const refs = userIds.map(id => this.firestore.doc(`users/${id}`))
    this.firestore.getAll(...refs).then(users => console.log(users.map(doc => doc.data())))
}

答案 7 :(得分:1)

在这里,您将使用Android SDK在Kotlin中执行类似的操作。
不一定是一次往返,但是它确实有效地将结果分组并避免了许多嵌套的回调。

val userIds = listOf("123", "456")
val userTasks = userIds.map { firestore.document("users/${it!!}").get() }

Tasks.whenAllSuccess<DocumentSnapshot>(userTasks).addOnSuccessListener { documentList ->
    //Do what you need to with the document list
}

请注意,获取特定文档比获取所有文档并过滤结果要好得多。这是因为Firestore向您收取查询结果集的费用。

答案 8 :(得分:1)

对于那些想使用 Angular 做这件事的人,这里有一个例子:

首先需要导入一些库:(必须预先安装)

import * as firebase from 'firebase/app'
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'

集合的一些配置:

yourCollection: AngularFirestoreCollection;

constructor(
    private _db : AngularFirestore,
) { 
    // this is your firestore collection
    this.yourCollection = this._db.collection('collectionName');
}

这里是进行查询的方法:('products_id' 是一个 id 数组)

getProducts(products_ids) {
    var queryId = firebase.firestore.FieldPath.documentId();
    this.yourCollection.ref.where(queryId, 'in', products_ids).get()
        .then(({ docs }) => {
            console.log(docs.map(doc => doc.data()))
        })
}

答案 9 :(得分:0)

目前在Firestore中似乎不可能。我不明白为什么亚历山大的答案被接受,他提出的解决方案只返回“用户”集合中的所有文件。

根据您的需要,您应该考虑复制需要显示的相关数据,并在需要时仅请求完整的文档。

答案 10 :(得分:0)

最好的办法是 使用Promise.all作为客户端,然后必须等待.all读取,然后才能继续。

重复读取并让它们独立解析。在客户端,这可能归结为具有多个进度加载程序映像独立解析为值的UI。但是,这比冻结整个客户端直到.all读取解析更好。

因此,立即将所有同步结果转储到视图中,然后让异步结果在解析时分别进入。这似乎有些微不足道,但是如果您的客户的互联网连接状况不佳(例如我目前在这家咖啡店),那么将整个客户体验冻结几秒钟可能会导致“此应用很烂”的体验。

答案 11 :(得分:0)

我希望这对您有帮助,对我有用。

getCartGoodsData(id) {

    const goodsIDs: string[] = [];

    return new Promise((resolve) => {
      this.fs.firestore.collection(`users/${id}/cart`).get()
        .then(querySnapshot => {
          querySnapshot.forEach(doc => {
            goodsIDs.push(doc.id);
          });

          const getDocs = goodsIDs.map((id: string) => {
            return this.fs.firestore.collection('goods').doc(id).get()
              .then((docData) => {
                return docData.data();
              });
          });

          Promise.all(getDocs).then((goods: Goods[]) => {
            resolve(goods);
          });
        });
    });
  }

答案 12 :(得分:0)

是的,这是可能的。 Firestore 的 .NET SDK 示例:

/*List of document references, for example:
    FirestoreDb.Collection(ROOT_LEVEL_COLLECTION).Document(DOCUMENT_ID);*/
    List<DocumentReference> docRefList = YOUR_DOCUMENT_REFERENCE_LIST;
    
    // Required fields of documents, not necessary while fetching entire documents
    FieldMask fieldMask = new FieldMask(FIELD-1, FIELD-2, ...);
    
    // With field mask
    List<DocumentSnapshot> documentSnapshotsMasked = await FirestoreDb.GetAllSnapshotsAsync(docRefList, fieldMask);
    
    // Without field mask
    List<DocumentSnapshot>documentSnapshots = await FirestoreDb.GetAllSnapshotsAsync(docRefList);

.NET 中的文档:

  1. Get all snapshots

  2. Field mask