Google Firestore - एक दौर की यात्रा में कई आईडी द्वारा दस्तावेज़ कैसे प्राप्त करें?


98

मैं सोच रहा हूं कि क्या फायरस्टार को एक राउंड ट्रिप (नेटवर्क कॉल) में आईडी की सूची से कई दस्तावेज प्राप्त करना संभव है।


4
आपको लगता है कि राउंडट्रिप्स आपके ऐप में प्रदर्शन की समस्याएं पैदा कर रहे हैं। मैं ऐसा नहीं मानूंगा। फायरबेस के पास ऐसे मामलों में अच्छा प्रदर्शन करने का इतिहास है, क्योंकि यह अनुरोधों को पाइपलाइन करता है । जबकि मैंने जाँच नहीं की है कि फायरस्टार इस परिदृश्य में कैसे व्यवहार करता है, मुझे यह मानने से पहले कि यह मौजूद है, प्रदर्शन समस्या का प्रमाण देखना अच्छा लगेगा।
फ्रैंक वैन पफलेन

1
चलो मैं दस्तावेजों की जरूरत है कहते हैं a, b, cकुछ करने के लिए। मैं सभी तीनों के लिए अलग-अलग अनुरोध करता हूं। a100ms लेता है, b150ms लेता है, और c3000ms लेता है। परिणामस्वरूप, मुझे कार्य करने के लिए 3000ms की प्रतीक्षा करनी होगी। यह उनके होने जा रहा है max। यह जोखिम भरा होने वाला है जब लाने के लिए दस्तावेजों की संख्या बड़ी हो। नेटवर्क की स्थिति पर निर्भर करता है, मुझे लगता है कि यह एक समस्या बन सकती है।
जून

1
उन सभी को भेजने के रूप में एक ही SELECT * FROM docs WHERE id IN (a,b,c)समय हालांकि की एक ही राशि नहीं ले जाएगा? मुझे अंतर नहीं दिखता है, क्योंकि कनेक्शन एक बार स्थापित हो गया है और बाकी उस पर पाइपलाइन है। समय (कनेक्शन की प्रारंभिक स्थापना के बाद) सभी दस्तावेजों का लोड समय + 1 गोल यात्रा, दोनों दृष्टिकोणों के लिए समान है। यदि यह आपके लिए अलग व्यवहार करता है, तो क्या आप एक नमूना साझा कर सकते हैं (जैसा कि मेरे जुड़े प्रश्न में है)?
फ्रैंक वैन पफलेन

मुझे लगता है कि मैंने तुम्हें खो दिया। जब आप कहते हैं कि यह पाइपलाइज्ड है, तो क्या आपका मतलब है कि फायरस्टार स्वचालित रूप से समूह और डेटाबेस के लिए एक दौर की यात्रा में अपने सर्वर को प्रश्न भेजें?
जून

FYI करें, एक राउंड ट्रिप से मेरा क्या मतलब है क्लाइंट से डेटाबेस के लिए एक नेटवर्क कॉल है। मैं पूछ रहा हूं कि क्या फायरस्टार द्वारा कई प्रश्नों को स्वचालित रूप से एक राउंड ट्रिप के रूप में वर्गीकृत किया गया है, या क्या कई प्रश्नों को समानांतर में कई राउंड ट्रिप के रूप में प्रदर्शित किया गया है।
जून

जवाबों:


88

यदि आप नोड के भीतर हैं:

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])}`);
* });
*/

यह विशेष रूप से सर्वर एसडीके के लिए है

अद्यतन: "क्लाउड फायरस्टार [क्लाइंट-साइड sdk] अब क्वेरी में समर्थन करता है!"

https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html

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


28
() Firestore.getAll (... arrayOfReferences) तो फिर: किसी दस्तावेज़ के संदर्भ की एक गतिशील रूप से उत्पन्न सरणी के साथ इस विधि कॉल करने के लिए देख लिए, आप इस तरह यह कर सकते हैं
Horea

1
मुझे क्षमा करें @KamanaKisinga ... मैंने लगभग एक साल में कोई फायरबेस सामान नहीं किया है और वास्तव में इस समय मदद नहीं कर सकता (अरे देखो, मैंने वास्तव में आज से एक साल पहले यह उत्तर पोस्ट किया था!)
निक फ्रांसेचिना

2
क्लाइंट-साइड SDK अब यह कार्यक्षमता भी प्रदान करते हैं। उदाहरण के लिए जियोडोनरा का जवाब देखें: stackoverflow.com/a/58780369
फ्रैंक वैन पफलेन

4
चेतावनी: फ़िल्टर में वर्तमान में 10 आइटमों तक सीमित है। तो शायद आपको पता चलेगा कि जब आप प्रोडक्शन को हिट करने वाले हों तो यह बेकार है।
मार्टिन क्रेमर

6
वास्तव में आपको उपयोग करने की आवश्यकता है firebase.firestore.FieldPath.documentId()और नहीं'id'
मैडॉक्स

20

उन्होंने सिर्फ इस कार्यक्षमता, https://firebase.googleblog.com/2019/11/cloud-firestore-now-supports-in-queries.html की घोषणा की है ।

अब आप जैसे प्रश्नों का उपयोग कर सकते हैं, लेकिन ध्यान रखें कि इनपुट का आकार 10 से अधिक नहीं हो सकता है।

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


जहाँ की बजाय जहाँ एक प्रश्न है। और मुझे पता नहीं है कि दस्तावेज़ों की एक सूची से कई दस्तावेज़ों के लिए क्वेरी कैसे डिज़ाइन की जाती है जो विशिष्ट संग्रह से संबंधित है। कृपया मदद कीजिए।
संकलित त्रुटि

16
@Compileerrorend क्या आप यह कोशिश कर सकते हैं? db.collection('users').where(firebase.firestore.FieldPath.documentId(), 'in',["123","345","111"]).get()
ज्‍डोनारा

धन्यवाद, विशेष रूप सेfirebase.firestore.FieldPath.documentId()
चेर्निव

10

नहीं, अभी क्लाउड फायरस्टार एसडीके का उपयोग करके कई रीड रिक्वेस्ट को बैचने का कोई तरीका नहीं है और इसलिए यह गारंटी देने का कोई तरीका नहीं है कि आप एक बार में सभी डेटा पढ़ सकते हैं।

हालाँकि जैसा कि फ्रैंक वैन पफलेन ने कहा है कि ऊपर की टिप्पणियों में इसका मतलब यह नहीं है कि 3 दस्तावेज़ लाने से यह दस्तावेज़ प्राप्त करने के लिए 3x जितना धीमा होगा। यहां किसी निष्कर्ष पर पहुंचने से पहले अपना माप प्रदर्शन करना सबसे अच्छा है।


1
बात यह है कि मैं फायरस्टार के प्रदर्शन से पहले फायरस्टार के प्रदर्शन के लिए सैद्धांतिक सीमाएं जानना चाहता हूं। मैं माइग्रेट नहीं करना चाहता और फिर महसूस करता हूं कि यह मेरे उपयोग के मामले के लिए पर्याप्त नहीं है।
जून १

2
हाय, यहाँ भी कोसे का विचार है। मान लें कि मैंने अपने सभी मित्र के आईडी की सूची संग्रहीत कर ली है और संख्या 500 है। मैं सूची को 1 रीड कॉस्ट में प्राप्त कर सकता हूं, लेकिन उनके नाम और फोटो को प्रदर्शित करने के लिए, मुझे 500 रीड की लागत आएगी।
तापस मुखर्जी

1
यदि आप 500 दस्तावेज़ पढ़ने की कोशिश कर रहे हैं, तो इसमें 500 रीड्स लगते हैं। यदि आप उन सभी सूचनाओं को जोड़ते हैं जो आपको सभी 500 दस्तावेज़ों से एक ही अतिरिक्त दस्तावेज़ में चाहिए, तो यह केवल एक ही पढ़ती है। कहा जाता है कि क्लाउड फायरस्टार सहित अधिकांश NoSQL डेटाबेस में डेटा डुप्लिकेट काफी सामान्य है।
फ्रैंक वैन पफेलन

1
@FrankvanPuffelen उदाहरण के लिए, mongoDb में, आप इस stackoverflow.com/a/32264630/648851 की तरह ObjectId का उपयोग कर सकते हैं ।
सिटियन लियू

2
जैसे @FrankvanPuffelen ने कहा, डेटा डुप्लिकेटेशन NoSQL डेटाबेस में बहुत आम है। यहां आपको अपने आप से पूछना होगा कि इन आंकड़ों को कितनी बार पढ़ना आवश्यक है, और उन्हें कितने अद्यतित होने की आवश्यकता है। यदि आप 500 उपयोगकर्ताओं की जानकारी संग्रहीत करते हैं, तो उनका नाम + फोटो + आईडी बताएं, आप उन्हें एक रीड में प्राप्त कर सकते हैं। लेकिन अगर आपको उन्हें अद्यतित करने की आवश्यकता है, तो संभवतः आपको प्रत्येक बार उपयोगकर्ता द्वारा अपना नाम / फोटो अपडेट करने के लिए इन संदर्भों को अपडेट करने के लिए क्लाउड फ़ंक्शन का उपयोग करना होगा, इसलिए क्लाउड फ़ंक्शन चला रहा है + कुछ लेखन कार्य कर रहा है। कोई "सही" / "बेहतर" कार्यान्वयन नहीं है, यह सिर्फ आपके उपयोग के मामले पर निर्भर करता है।
शंखम

9

व्यवहार में आप इस तरह 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())))
}

2
यह वास्तव में चयनित उत्तर होना चाहिए क्योंकि यह आपको 10 से अधिक आईडी का उपयोग करने देता है
sshah98

9

आप इस तरह एक समारोह का उपयोग कर सकते हैं:

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

इसे एक एकल आईडी के साथ कहा जा सकता है:

getById('collection', 'some_id')

या आईडी की एक सरणी:

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

5

निश्चित रूप से ऐसा करने का सबसे अच्छा तरीका है क्लाउड फंक्शन में फायरस्टार की वास्तविक क्वेरी को लागू करना? इसके बाद क्लाइंट से फायरबेस तक केवल एक ही राउंड ट्रिप कॉल होगी, जो ऐसा लगता है कि आप क्या पूछ रहे हैं।

आप वास्तव में इस सर्वर साइड की तरह अपने सभी डेटा एक्सेस लॉजिक को रखना चाहते हैं।

आंतरिक रूप से फायरबेस के लिए समान संख्या में कॉल की संभावना होगी, लेकिन वे सभी बाहरी नेटवर्क के बजाय Google के सुपर-फास्ट इंटरकनेक्ट पर होंगे, और पाइपलाइनिंग के साथ संयुक्त होगा जिसे फ्रैंक वैन पफलेन ने समझाया है, आपको उत्कृष्ट प्रदर्शन मिलना चाहिए यह दृष्टिकोण।


3
क्लाउड फ़ंक्शन में कार्यान्वयन को संग्रहीत करना कुछ मामलों में सही निर्णय है जहां आपके पास जटिल तर्क है, लेकिन शायद उस मामले में नहीं जहां आप सिर्फ एक सूची को कई आईडी के साथ मर्ज करना चाहते हैं। आप जो खोते हैं वह क्लाइंट साइड कैशिंग और नियमित कॉल से मानकीकृत रिटर्न फॉर्मेटिंग है। जब मैंने एप्रोच का उपयोग किया तो मेरे एप्स में कुछ मामलों में इसे हल करने की तुलना में अधिक प्रदर्शन की समस्या पैदा हुई।
यिर्मयाह

3

यदि आप स्पंदन का उपयोग कर रहे हैं, तो आप निम्न कार्य कर सकते हैं:

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

यह एक फ्यूचर को लौटा देगा List<DocumentSnapshot>जिसमें आप फिट होने के साथ ही इसे पुन: व्यवस्थित कर सकते हैं।


2

यहां बताया गया है कि आप एंड्रॉइड एसडीके के साथ कोटलिन में कुछ ऐसा कैसे करेंगे।
जरूरी नहीं कि यह एक दौर की यात्रा में हो, लेकिन यह प्रभावी रूप से परिणाम का समूह बनाता है और कई नेस्टेड कॉलबैक से बचता है।

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
}

ध्यान दें कि सभी दस्तावेजों को लाने और परिणाम को फ़िल्टर करने की तुलना में विशिष्ट दस्तावेज़ प्राप्त करना बेहतर है। ऐसा इसलिए है क्योंकि फायरस्टार आपसे क्वेरी परिणाम सेट के लिए शुल्क लेता है।


1
अच्छी तरह से काम करता है, वास्तव में मैं क्या देख रहा था!
जॉर्जी

0

फिलहाल फायरस्टार में यह संभव नहीं लगता। मुझे समझ नहीं आ रहा है कि अलेक्जेंडर का जवाब क्यों स्वीकार किया जाता है, जिस समाधान का वह प्रस्ताव करता है वह "उपयोगकर्ता" संग्रह में सभी दस्तावेजों को वापस करता है।

आपको जो करने की आवश्यकता है, उसके आधार पर, आपको उस प्रासंगिक डेटा को डुप्लिकेट करना चाहिए, जिसे आपको प्रदर्शित करने की आवश्यकता है और आवश्यकता होने पर केवल एक पूर्ण दस्तावेज़ का अनुरोध करें।


0

जो सबसे अच्छा आप कर सकते हैं वह आपके ग्राहक के रूप में उपयोग नहीं कियाPromise.all जाता है तो .allआगे बढ़ने से पहले रीड्स का इंतजार करना चाहिए ।

रीडर्स को अलग करें और उन्हें स्वतंत्र रूप से हल करने दें। क्लाइंट की ओर से, यह संभवतः यूआई के लिए उबलता है जिसमें कई प्रगति लोडर चित्र हैं जो स्वतंत्र रूप से मूल्यों का समाधान करते हैं। हालांकि, यह पूरे क्लाइंट .allको फ्रीज़ करने से बेहतर है जब तक कि रीड्स हल न हो जाए।

इसलिए, सभी सिंक्रोनस परिणामों को तुरंत दृश्य में डंप करें, फिर असिंक्रोनस परिणामों को व्यक्तिगत रूप से हल करने दें। यह पेटी डिस्टिंक्शन जैसा लग सकता है, लेकिन यदि आपके क्लाइंट में इंटरनेट कनेक्टिविटी खराब है (जैसे कि वर्तमान में मैं इस कॉफी शॉप में हूं), तो कई सेकंड के लिए पूरे क्लाइंट अनुभव को फ्रीज करने से 'इस ऐप बेकार' का अनुभव होगा।


2
यह अतुल्यकालिक है, उपयोग करने के लिए बहुत सारे उपयोग के मामले हैं Promise.all... इसके लिए कुछ भी "फ्रीज" करना जरूरी नहीं है - आपको कुछ सार्थक करने में सक्षम होने से पहले सभी डेटा के लिए प्रतीक्षा करने की आवश्यकता हो सकती है
रयान टेलर

ऐसे कई उपयोग के मामले हैं जब आपको अपने सभी डेटा को लोड करने की आवश्यकता होती है, इसलिए प्रतीक्षा (एक उपयुक्त संदेश के साथ एक स्पिनर की तरह, आपको यूआई जैसा कोई यूज़ करने के लिए "फ्रीज" करने की आवश्यकता नहीं है) पूरी तरह से प्रोमिस.all द्वारा आवश्यक हो सकती है। यह वास्तव में इस बात पर निर्भर करता है कि आप किस तरह के उत्पादों का निर्माण कर रहे हैं। इस तरह की टिप्पणियाँ मेरे अपने विचार बहुत ही अप्रासंगिक हैं और इसमें कोई "सर्वश्रेष्ठ" शब्द नहीं होना चाहिए। यह वास्तव में हर अलग-अलग उपयोग के मामलों पर निर्भर करता है जो एक उपयोगकर्ता का सामना कर सकता है और आपका ऐप क्या कर रहा है।
शंखम

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);
          });
        });
    });
  }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.