ฉันสงสัยว่าเป็นไปได้หรือไม่ที่จะรับเอกสารหลายรายการตามรายการรหัสในการเดินทางไปกลับครั้งเดียว (การโทรผ่านเครือข่าย) ไปยัง Firestore
Google Firestore - วิธีรับเอกสารหลายรหัสในการเดินทางไปกลับครั้งเดียว
คำตอบ (13)
หากคุณอยู่ในโหนด:
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 เซิร์ฟเวอร์โดยเฉพาะ
อัปเดต: Cloud Firestore [sdk ฝั่งไคลเอ็นต์] รองรับ IN Queries แล้ว!
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)
ล่ะถ้าตัวดำเนินการสเปรดยังไม่รองรับ?
- person Julian Paolo Dayag; 12.02.2019
firebase.firestore.FieldPath.documentId()
ไม่ใช่ '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
พวกเขาเพิ่งประกาศฟังก์ชันการทำงานนี้ https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html
ตอนนี้คุณสามารถใช้ข้อความค้นหาได้ แต่โปรดทราบว่าขนาดอินพุตต้องไม่เกิน 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
ในทางปฏิบัติ คุณจะใช้ 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())))
}
คุณสามารถใช้ฟังก์ชันเช่นนี้:
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'])
ไม่ ขณะนี้ยังไม่มีวิธีแบทช์คำขออ่านหลายรายการโดยใช้ Cloud Firestore SDK ดังนั้นจึงไม่มีวิธีรับประกันว่าคุณจะสามารถอ่านข้อมูลทั้งหมดได้ในคราวเดียว
อย่างไรก็ตาม ตามที่ Frank van Puffelen ได้กล่าวไว้ในความคิดเห็นข้างต้น ไม่ได้หมายความว่าการดึงเอกสาร 3 รายการจะช้ากว่าการดึงเอกสารฉบับเดียวถึง 3 เท่า วิธีที่ดีที่สุดคือทำการวัดผลของคุณเองก่อนที่จะได้ข้อสรุปที่นี่
หากคุณใช้ flutter คุณสามารถทำสิ่งต่อไปนี้:
Firestore.instance.collection('your collection name').where(FieldPath.documentId, whereIn:[list containing multiple document IDs]).getDocuments();
สิ่งนี้จะส่งคืนอนาคตที่มี List<DocumentSnapshot>
ซึ่งคุณสามารถวนซ้ำได้ตามที่คุณรู้สึกเหมาะสม
แน่นอนว่าวิธีที่ดีที่สุดในการทำเช่นนี้คือการใช้แบบสอบถามจริงของ Firestore ในฟังก์ชั่นคลาวด์ จากนั้นจะมีการโทรไปกลับเพียงครั้งเดียวจากไคลเอนต์ไปยัง Firebase ซึ่งดูเหมือนว่าจะเป็นสิ่งที่คุณต้องการ
คุณอยากจะรักษาตรรกะการเข้าถึงข้อมูลทั้งหมดของคุณไว้เหมือนกับฝั่งเซิร์ฟเวอร์นี้อยู่แล้ว
ภายในมีแนวโน้มที่จะมีจำนวนการโทรไปยัง Firebase เท่ากัน แต่การโทรทั้งหมดจะผ่านการเชื่อมต่อที่รวดเร็วเป็นพิเศษของ Google แทนที่จะเป็นเครือข่ายภายนอก และเมื่อรวมกับไปป์ไลน์ที่ Frank van Puffelen อธิบายไว้ คุณควรได้รับประสิทธิภาพที่ยอดเยี่ยมจาก แนวทางนี้
ต่อไปนี้คือวิธีดำเนินการเช่นนี้ใน 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
}
โปรดทราบว่าการดึงเอกสารเฉพาะเจาะจงดีกว่าการดึงเอกสารทั้งหมดแล้วกรองผลลัพธ์ เนื่องจาก Firestore เรียกเก็บเงินคุณสำหรับชุดผลลัพธ์การสืบค้น
ฉันหวังว่าสิ่งนี้จะช่วยคุณได้ มันได้ผลสำหรับฉัน
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);
});
});
});
}
สำหรับผู้ที่ต้องการใช้ 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' คือ 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()))
})
}
ใช่มันเป็นไปได้ ตัวอย่างใน .NET SDK สำหรับ 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);
เอกสารประกอบใน .NET:
สิ่งที่ดีที่สุดที่คุณสามารถทำได้คือ ไม่ ใช้ Promise.all
เนื่องจากไคลเอ็นต์ของคุณต้องรอ .all
การอ่านก่อนที่จะดำเนินการต่อ
ทำซ้ำการอ่านและปล่อยให้แก้ไขอย่างอิสระ ในฝั่งไคลเอ็นต์ สิ่งนี้อาจเดือดลงไปที่ UI ที่มีอิมเมจตัวโหลดความคืบหน้าหลายตัวแก้ไขเป็นค่าอย่างอิสระ อย่างไรก็ตาม วิธีนี้ดีกว่าการแช่แข็งไคลเอ็นต์ทั้งหมดจนกว่า .all
การอ่านจะได้รับการแก้ไข
ดังนั้น ให้ดัมพ์ผลลัพธ์แบบซิงโครนัสทั้งหมดไปยังมุมมองทันที จากนั้นปล่อยให้ผลลัพธ์แบบอะซิงโครนัสเข้ามาในขณะที่แก้ไขทีละรายการ นี่อาจดูเหมือนเป็นข้อแตกต่างเล็กๆ น้อยๆ แต่หากลูกค้าของคุณมีการเชื่อมต่ออินเทอร์เน็ตที่ไม่ดี (เหมือนกับที่ฉันใช้ที่ร้านกาแฟแห่งนี้ในปัจจุบัน) การหยุดประสบการณ์ของลูกค้าทั้งหมดเป็นเวลาหลายวินาทีจะส่งผลให้ประสบการณ์ 'แอปนี้ห่วย'
Promise.all
... โดยไม่จำเป็นต้องหยุดการทำงานใดๆ เลย คุณอาจต้องรอข้อมูลทั้งหมดก่อนจึงจะสามารถทำอะไรที่มีความหมายได้
- person Ryan Taylor; 08.03.2019
a
,b
,c
เพื่อทำบางสิ่งบางอย่าง ฉันขอทั้งสามคำขอพร้อมกันโดยแยกกันa
ใช้เวลา 100 มิลลิวินาที,b
ใช้เวลา 150 มิลลิวินาที และc
ใช้เวลา 3,000 มิลลิวินาที ด้วยเหตุนี้ ฉันต้องรอถึง 3,000 มิลลิวินาทีจึงจะทำงานได้ มันจะเป็นmax
ในนั้น จะมีความเสี่ยงมากขึ้นเมื่อเอกสารที่จะดึงข้อมูลมีจำนวนมาก ขึ้นอยู่กับสถานะเครือข่าย ฉันคิดว่านี่อาจเป็นปัญหาได้ - person Joon   schedule 13.10.2017SELECT * FROM docs WHERE id IN (a,b,c)
เดียวใช้เวลานานเท่ากันใช่ไหม ฉันไม่เห็นความแตกต่าง เนื่องจากการเชื่อมต่อเกิดขึ้นเพียงครั้งเดียวและส่วนที่เหลือจะถูกส่งต่อไปยังจุดนั้น เวลา (หลังจากสร้างการเชื่อมต่อครั้งแรก) คือเวลาโหลดเอกสารทั้งหมด + เดินทางไปกลับ 1 ครั้ง ซึ่งเท่ากันสำหรับทั้งสองวิธี ถ้ามันทำงานแตกต่างออกไปสำหรับคุณ คุณช่วยแบ่งปันตัวอย่าง (ตามคำถามที่เชื่อมโยงของฉัน) ได้ไหม - person Frank van Puffelen   schedule 13.10.2017n
รายการพร้อมกันสำหรับn
รายการ แทนที่จะเรียกผ่านเครือข่ายเพียงครั้งเดียวที่ทำการสืบค้นn
รายการพร้อมกัน - person Joon   schedule 14.10.2017N*(read_time+transfer_time+latency)
หากพวกมันถูกไปป์ไลน์ มันจะใกล้กับN*(transfer_time)+read_time+latency
มากขึ้น - person Frank van Puffelen   schedule 14.10.2017