Saya bertanya-tanya apakah mungkin untuk mendapatkan banyak dokumen berdasarkan daftar id dalam satu perjalanan pulang pergi (panggilan jaringan) ke Firestore.
Google Firestore - bagaimana cara mendapatkan dokumen dengan banyak id dalam satu perjalanan pulang pergi?
Jawaban (13)
jika Anda berada dalam 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])}`);
* });
*/
Ini khusus untuk SDK server
PEMBARUAN: Cloud Firestore [sdk sisi klien] Kini Mendukung Kueri IN!
https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html
myCollection.where(firestore.FieldPath.documentId(), 'in', ["123","456","789"])
firestore.getAll.call(null, arrayOfReferences)
jika operator spread belum support?
- person Julian Paolo Dayag; 12.02.2019
firebase.firestore.FieldPath.documentId()
dan bukan 'id'
- person Maddocks; 26.01.2020
List<String> lst;
, FirebaseFirestore.getInstance().collection("collection_name").whereIn(FieldPath.documentId(), lst).get().addOnCompleteListener(...);
- person Alaa M.; 04.07.2020
Mereka baru saja mengumumkan fungsi ini, https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html .
Sekarang Anda dapat menggunakan kueri seperti, tetapi ingat bahwa ukuran masukan tidak boleh lebih besar dari 10.
userCollection.where('uid', 'in', ["1231","222","2131"])
db.collection('users').where(firebase.firestore.FieldPath.documentId(), 'in',["123","345","111"]).get()
- person jeadonara; 03.12.2019
firebase.firestore.FieldPath.documentId()
- person Ivan Chernykh; 22.12.2019
Dalam praktiknya Anda akan menggunakan firestore.getAll seperti ini
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()))
}
atau dengan sintaks janji
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())))
}
Anda bisa menggunakan fungsi seperti ini:
function getById (path, ids) {
return firestore.getAll(
[].concat(ids).map(id => firestore.doc(`${path}/${id}`))
)
}
Itu bisa dipanggil dengan satu ID:
getById('collection', 'some_id')
atau serangkaian ID:
getById('collection', ['some_id', 'some_other_id'])
Tidak, saat ini tidak ada cara untuk mengelompokkan beberapa permintaan baca menggunakan Cloud Firestore SDK dan oleh karena itu tidak ada cara untuk menjamin bahwa Anda dapat membaca semua data sekaligus.
Namun seperti yang dikatakan Frank van Puffelen dalam komentar di atas, hal ini tidak berarti bahwa mengambil 3 dokumen akan 3x lebih lambat daripada mengambil satu dokumen. Yang terbaik adalah melakukan pengukuran Anda sendiri sebelum mencapai kesimpulan di sini.
Jika Anda menggunakan flutter, Anda dapat melakukan hal berikut:
Firestore.instance.collection('your collection name').where(FieldPath.documentId, whereIn:[list containing multiple document IDs]).getDocuments();
Ini akan mengembalikan Masa Depan yang berisi List<DocumentSnapshot>
yang dapat Anda ulangi sesuai keinginan Anda.
Tentunya cara terbaik untuk melakukannya adalah dengan mengimplementasikan kueri Firestore yang sebenarnya di Cloud Function? Maka hanya akan ada satu panggilan pulang pergi dari klien ke Firebase, yang sepertinya adalah apa yang Anda minta.
Anda benar-benar ingin mempertahankan semua logika akses data Anda seperti sisi server ini.
Secara internal kemungkinan akan ada jumlah panggilan yang sama ke Firebase itu sendiri, namun semuanya akan dilakukan melalui interkoneksi super cepat Google, bukan melalui jaringan eksternal, dan dikombinasikan dengan pipeline yang dijelaskan oleh Frank van Puffelen, Anda akan mendapatkan performa luar biasa dari pendekatan ini.
Inilah cara Anda melakukan hal seperti ini di Kotlin dengan Android SDK.
Mungkin tidak harus dalam satu perjalanan bolak-balik, namun hasilnya mengelompokkan secara efektif dan menghindari banyak callback yang bersarang.
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
}
Perhatikan bahwa mengambil dokumen tertentu jauh lebih baik daripada mengambil semua dokumen dan memfilter hasilnya. Hal ini karena Firestore menagih Anda untuk kumpulan hasil kueri.
Saya harap ini membantu Anda, ini berhasil untuk saya.
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);
});
});
});
}
Bagi yang ingin melakukannya menggunakan Angular, berikut contohnya:
Pertama, beberapa impor perpustakaan diperlukan: (harus diinstal sebelumnya)
import * as firebase from 'firebase/app'
import { AngularFirestore, AngularFirestoreCollection } from '@angular/fire/firestore'
Beberapa konfigurasi untuk koleksi:
yourCollection: AngularFirestoreCollection;
constructor(
private _db : AngularFirestore,
) {
// this is your firestore collection
this.yourCollection = this._db.collection('collectionName');
}
Berikut adalah metode untuk melakukan query: ('products_id' adalah Array of ids)
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()))
})
}
Ya, itu mungkin. Contoh di .NET SDK untuk Firestore:
/*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);
Dokumentasi dalam .NET:
Hal terbaik yang dapat Anda lakukan adalah tidak menggunakan Promise.all
sebagai klien Anda dan kemudian harus menunggu .all
pembacaan sebelum melanjutkan.
Ulangi bacaannya dan biarkan mereka menyelesaikannya secara mandiri. Di sisi klien, ini mungkin bermuara pada UI yang memiliki beberapa gambar pemuat kemajuan yang menentukan nilai secara independen. Namun, ini lebih baik daripada membekukan seluruh klien sampai .all
pembacaan teratasi.
Oleh karena itu, segera buang semua hasil sinkron ke tampilan, lalu biarkan hasil asinkron masuk saat diselesaikan, satu per satu. Ini mungkin tampak seperti perbedaan kecil, tetapi jika klien Anda memiliki konektivitas Internet yang buruk (seperti yang saya alami saat ini di kedai kopi ini), membekukan seluruh pengalaman klien selama beberapa detik kemungkinan besar akan menghasilkan pengalaman 'aplikasi ini jelek'.
Promise.all
... tidak harus membekukan apa pun – Anda mungkin perlu menunggu semua data sebelum dapat melakukan sesuatu yang berarti
- person Ryan Taylor; 08.03.2019
a
,b
,c
untuk melakukan sesuatu. Saya meminta ketiganya secara paralel dalam permintaan terpisah.a
membutuhkan waktu 100 md,b
membutuhkan waktu 150 md, danc
membutuhkan waktu 3000 md. Akibatnya, saya harus menunggu 3000 ms untuk melakukan tugas tersebut. Ini akan menjadimax
dari mereka. Akan lebih berisiko bila jumlah dokumen yang harus diambil banyak. Tergantung pada status jaringan, menurut saya ini bisa menjadi masalah. - person Joon   schedule 13.10.2017SELECT * FROM docs WHERE id IN (a,b,c)
membutuhkan waktu yang sama? Saya tidak melihat perbedaannya, karena koneksi dibuat satu kali dan sisanya disalurkan melalui saluran tersebut. Waktu (setelah koneksi awal dibuat) adalah waktu buka semua dokumen + 1 perjalanan pulang pergi, sama untuk kedua pendekatan. Jika perilakunya berbeda bagi Anda, dapatkah Anda membagikan sampelnya (seperti dalam pertanyaan tertaut saya)? - person Frank van Puffelen   schedule 13.10.2017n
panggilan jaringan secara paralel untukn
item, bukan hanya satu panggilan jaringan yang melakukann
kueri sekaligus. - person Joon   schedule 14.10.2017N*(read_time+transfer_time+latency)
. Jika sudah disalurkan, mendekatiN*(transfer_time)+read_time+latency
. - person Frank van Puffelen   schedule 14.10.2017