谷歌火还原-如何通过多个 ID 在一个往返的几个文件?

我想知道是否有可能通过一次往返(网络调用)的 id 列表来获取多个文档到 Firestore 数据库。

83592 次浏览

不,现在还没有办法使用 Cloud FirestorSDK 批处理多个读取请求,因此也没有办法保证可以一次读取所有数据。

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

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

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

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

这是专门针对服务器 SDK 的

更新: < a href = “ https://firebase.googleblog.com/2019/11/Cloud-firestor- Now-support-IN-Queries.html”rel = “ noReferrer”> Cloud FiRecovery Now Support IN Query!

myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"])

当然,最好的方法是通过在一个云函数中实现实际的火恢复查询?然后只有一个来回电话从客户端到 Firebase,这似乎是你所要求的。

无论如何,您确实希望保留所有数据访问逻辑,就像这个服务器端一样。

在内部,可能会有相同数量的电话打到 Firebase 本身,但它们都将通过谷歌的超高速互连,而不是外部网络,结合流水线,Frank van Puffelen 解释说,你应该从这种方法获得出色的性能。

你可以使用这样的函数:

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

它可以用一个 ID 来调用:

getById('collection', 'some_id')

或 ID 数组:

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

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

迭代读取并让它们独立解析。在客户端,这可能归结为 UI 有几个进度加载程序映像独立地解析为值。但是,这比冻结整个客户端直到解析 .all读操作要好。

因此,立即将所有同步结果转储到视图中,然后让异步结果在解析时单独进入。这可能看起来有些微不足道,但是如果你的客户端网络连接很差(就像我现在在这家咖啡店) ,将整个客户端体验冻结几秒钟可能会导致“这个应用程序糟透了”的体验。

实际上你可以使用 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()))
}

或者用承诺语法

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

下面是你在 Kotlin 如何使用 Android SDK 做类似的事情。
可能不一定在一个往返过程中,但是它确实有效地对结果进行了分组,并避免了许多嵌套的回调。

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
}

请注意,获取特定文档要比获取所有文档并过滤结果好得多。这是因为火恢复对查询结果集收费。

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

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

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

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

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

如果你使用 颤抖,你可以做到以下几点:

Firestore.instance.collection('your_collection_name')
.where(FieldPath.documentId, whereIn:["list", "of", "document", "ids"])
.getDocuments();

这将返回一个包含 List<DocumentSnapshot>的 Future,您可以根据自己的感觉进行迭代。

对于那些想用 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 的 Array)

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

是的,这是可能的:

/*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. 拍下所有的快照

  2. 野战面罩

您可以使用文档 ID (最多10个)执行 IN 查询:

import {
query,
collection,
where,
getDocs,
documentId,
} from 'firebase/firestore';


export async function fetchAccounts(
ids: string[]
) {
// use lodash _.chunk, for example
const result = await Promise.all(
chunk(ids, 10).map(async (chunkIds) => {
const accounts = await getDocs(
query(
collection(firestore, 'accounts'),
where(documentId(), 'in', chunkIds)
));
return accounts.docs.filter(doc => doc.exists()).map(doc => doc.data());
})
);
return result.flat(1);
}

对于一些陷入同样问题的人来说 下面是一个示例代码:

List<String> documentsIds = {your document ids};


FirebaseFirestore.getInstance().collection("collection_name")
.whereIn(FieldPath.documentId(), documentsIds).get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : Objects.requireNonNull(task.getResult())) {
YourClass object = document.toObject(YourClass.class);
// add to your custom list
}
}
                

}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
e.printStackTrace();
}
});

与 Firebase 版本9(2021年12月更新) :

你可以使用带有 “哪里”子句的 “ documentId ()”“在”来进行 在一个往返过程中通过多个 ID 获取多个文档:

import {
query,
collection,
where,
documentId,
getDocs
} from "firebase/firestore";


const q = query(
collection(db, "products"),
where(documentId(), "in",
[
"8AVJvG81kDtb9l6BwfCa",
"XOHS5e3KY9XOSV7YYMw2",
"Y2gkHe86tmR4nC5PTzAx"
]
),
);


const productsDocsSnap = await getDocs(q);


productsDocsSnap.forEach((doc) => {
console.log(doc.data()); // "doc1", "doc2" and "doc3"
});

如果您使用的是 python firebase admin sdk,这就是您如何使用 uids 查询多个文档的方法

from firebase_admin import firestore
import firebase_admin
from google.cloud.firestore_v1.field_path import FieldPath


app = firebase_admin.initialize_app(cred)
client = firestore.client(app)


collection_ref = client.collection('collection_name')
query = collection_ref.where(FieldPath.document_id(), 'in', listOfIds)
docs = query.get()


for doc in docs:
print(doc.id, doc.to_dict())

不需要导入 FieldPath,您也可以简单地使用字符串 __name__