जहां फायरबेस में कई खंडों के आधार पर क्वेरी


244
{
"movies": {
    "movie1": {
        "genre": "comedy",
        "name": "As good as it gets",
        "lead": "Jack Nicholson"
    },
    "movie2": {
        "genre": "Horror",
        "name": "The Shining",
        "lead": "Jack Nicholson"
    },
    "movie3": {
        "genre": "comedy",
        "name": "The Mask",
        "lead": "Jim Carrey"
    }
  }  
 }

मैं एक फायरबेस नौसिखिया हूं। मैं ऊपर डेटा से एक परिणाम कैसे प्राप्त कर सकते हैं जहां genre = 'comedy'औरlead = 'Jack Nicholson' ?

आपके पास कौन से विकल्प हैं?

जवाबों:


238

फायरबेस की क्वेरी एपीआई का उपयोग करते हुए , आप इसे आज़मा सकते हैं:

// !!! THIS WILL NOT WORK !!!
ref
  .orderBy('genre')
  .startAt('comedy').endAt('comedy')
  .orderBy('lead')                  // !!! THIS LINE WILL RAISE AN ERROR !!!
  .startAt('Jack Nicholson').endAt('Jack Nicholson')
  .on('value', function(snapshot) { 
      console.log(snapshot.val()); 
  });

लेकिन जैसा कि Firebase से @RobDiMarco टिप्पणियों में कहता है:

एकाधिक orderBy()कॉल एक त्रुटि फेंक देंगे

इसलिए मेरे ऊपर का कोड काम नहीं करेगा

मुझे तीन दृष्टिकोणों का पता है जो काम करेंगे।

1. सर्वर पर सबसे अधिक फ़िल्टर करें, बाकी क्लाइंट पर करें

आप जो कुछ भी कर सकते हैं orderBy().startAt()./endAt(), वह सर्वर पर निष्पादित किया जाता है, शेष डेटा को नीचे खींचें और अपने क्लाइंट पर जावास्क्रिप्ट कोड में फ़िल्टर करें।

ref
  .orderBy('genre')
  .equalTo('comedy')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      if (movie.lead == 'Jack Nicholson') {
          console.log(movie);
      }
  });

2. एक संपत्ति जोड़ें जो उन मूल्यों को जोड़ती है जिन्हें आप फ़िल्टर करना चाहते हैं

यदि यह काफी अच्छा नहीं है, तो आपको अपने उपयोग-मामले की अनुमति देने के लिए अपने डेटा को संशोधित / विस्तारित करने पर विचार करना चाहिए। उदाहरण के लिए: आप शैली को एक एकल संपत्ति में ले जा सकते हैं, जिसे आप इस फिल्टर के लिए उपयोग करते हैं।

"movie1": {
    "genre": "comedy",
    "name": "As good as it gets",
    "lead": "Jack Nicholson",
    "genre_lead": "comedy_Jack Nicholson"
},...

आप अनिवार्य रूप से अपना स्वयं का मल्टी-कॉलम इंडेक्स बना रहे हैं और इसके साथ क्वेरी कर सकते हैं:

ref
  .orderBy('genre_lead')
  .equalTo('comedy_Jack Nicholson')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      console.log(movie);
  });

डेविड ईस्ट ने QueryBase नामक एक पुस्तकालय लिखा है जो इस तरह के गुणों को उत्पन्न करने में मदद करता है

आप रिश्तेदार / श्रेणी प्रश्न भी कर सकते हैं, मान लीजिए कि आप श्रेणी और वर्ष के अनुसार फिल्मों की अनुमति देना चाहते हैं। आप इस डेटा संरचना का उपयोग करेंगे:

"movie1": {
    "genre": "comedy",
    "name": "As good as it gets",
    "lead": "Jack Nicholson",
    "genre_year": "comedy_1997"
},...

और फिर 90 के दशक की कॉमेडी के लिए क्वेरी:

ref
  .orderBy('genre_year')
  .startAt('comedy_1990')
  .endAt('comedy_2000')
  .on('child_added', function(snapshot) { 
      var movie = snapshot.val();
      console.log(movie);
  });

यदि आपको केवल वर्ष से अधिक पर फ़िल्टर करने की आवश्यकता है, तो अवरोही क्रम में अन्य दिनांक भागों को जोड़ना सुनिश्चित करें, जैसे "comedy_1997-12-25"। इस तरह से लेज़रोग्राफ़िक ऑर्डर जो फायरबेस स्ट्रिंग मूल्यों पर करता है, कालानुक्रमिक क्रम के समान होगा।

एक संपत्ति में मूल्यों का यह संयोजन दो से अधिक मूल्यों के साथ काम कर सकता है, लेकिन आप केवल संयुक्त संपत्ति के अंतिम मूल्य पर एक सीमा फ़िल्टर कर सकते हैं।

इसका एक बहुत ही विशेष संस्करण फायरबेस के लिए जियोफायर लाइब्रेरी द्वारा लागू किया गया है । यह लाइब्रेरी किसी स्थान के अक्षांश और देशांतर को तथाकथित जिय्हाश में जोड़ती है , जिसका उपयोग फिर फायरबेस पर रियलटाइम रेंज क्वेरी करने के लिए किया जा सकता है।

3. प्रोग्रामेटिक रूप से एक कस्टम इंडेक्स बनाएं

फिर भी एक और विकल्प यह है कि इस नए क्वेरी एपीआई के जुड़ने से पहले हमने जो किया है, वह करें: एक अलग नोड में एक इंडेक्स बनाएं:

  "movies"
      // the same structure you have today
  "by_genre"
      "comedy"
          "by_lead"
              "Jack Nicholson"
                  "movie1"
              "Jim Carrey"
                  "movie3"
      "Horror"
          "by_lead"
              "Jack Nicholson"
                  "movie2"

संभवतः अधिक दृष्टिकोण हैं। उदाहरण के लिए, यह उत्तर वैकल्पिक ट्री-आकार वाले कस्टम इंडेक्स पर प्रकाश डालता है: https://stackoverflow.com/a/34105063


3
जब यह आधिकारिक तौर पर अगले सप्ताह जारी किया जाता है, तो कई orderBy()कॉल में त्रुटि होगी, क्योंकि ग्राहक वर्तमान में अप्रत्याशित परिणाम देते हैं। यह संभव है कि यह संयोग से आपके परीक्षण में काम आए, लेकिन इसे उदारतापूर्वक काम करने के लिए नहीं बनाया गया है (हालांकि हम इसे जोड़ना पसंद करेंगे!)।
रोब डायमरको

18
क्या यह 2016 में भी Firebase V3 के साथ प्रासंगिक है? क्या ऐसा करने के लिए बेहतर तरीके नहीं हैं?
पियर

27
हम .equalTo('comedy')इसके बजाय का उपयोग क्यों नहीं कर सकते .startAt('comedy').endAt('comedy')?
JCarlosR

41
यह 2018 है, क्या इसके लिए कोई सरल उपाय नहीं है? यह रिलेशनल डेटाबेस में क्वेरी 101 की तरह है। और एसक्यूएल # 8 के बारे में बात करते हुए डेविड के वीडियो पर सभी टिप्पणियां दीं, मुझे उम्मीद है कि Google अब तक इसे ठीक कर देगा। क्या मुझे कुछ अपडेट याद आया?
सांप

10
@Snake फ़रवरी 2019 और समस्या अभी भी तय नहीं है .... Google बहुत धीमा है।
सुपरटेकनोफॉफ़

48

मैंने एक निजी पुस्तकालय लिखा है जो आपको सर्वर पर किए गए सभी आदेशों के साथ कई मूल्यों द्वारा ऑर्डर करने की अनुमति देता है।

Querybase से मिलो!

Querybase एक Firebase डेटाबेस संदर्भ और उन क्षेत्रों की एक सरणी लेता है जिन पर आप अनुक्रमित करना चाहते हैं। जब आप नए रिकॉर्ड बनाते हैं तो यह स्वचालित रूप से कई क्वेरी के लिए अनुमति देने वाली कुंजी की पीढ़ी को संभाल लेगा। चेतावनी यह है कि यह केवल सीधे समतुल्यता (किसी से कम या अधिक से अधिक) का समर्थन नहीं करता है।

const databaseRef = firebase.database().ref().child('people');
const querybaseRef = querybase.ref(databaseRef, ['name', 'age', 'location']);

// Automatically handles composite keys
querybaseRef.push({ 
  name: 'David',
  age: 27,
  location: 'SF'
});

// Find records by multiple fields
// returns a Firebase Database ref
const queriedDbRef = querybaseRef
 .where({
   name: 'David',
   age: 27
 });

// Listen for realtime updates
queriedDbRef.on('value', snap => console.log(snap));

आपके पुस्तकालय के लिए कोई टाइपस्क्रिप्ट परिभाषा उपलब्ध है?
लेवी फुलर

1
यह टीएस में लिखा है! तो बस आयात करें :)
डेविड ईस्ट

7
क्या आप जानते हैं कि उन्होंने डेटाबेस को इतना प्रतिबंधक क्यों बनाया?
गत

1
IOS स्विफ्ट / एंड्रॉइड वर्जन करने का कोई भी विकल्प
mding5692

1
डेविड, किसी भी Android / जावा तुल्यता?
सांप

3
var ref = new Firebase('https://your.firebaseio.com/');

Query query = ref.orderByChild('genre').equalTo('comedy');
query.addValueEventListener(new ValueEventListener() {
    @Override
    public void onDataChange(DataSnapshot dataSnapshot) {
        for (DataSnapshot movieSnapshot : dataSnapshot.getChildren()) {
            Movie movie = dataSnapshot.getValue(Movie.class);
            if (movie.getLead().equals('Jack Nicholson')) {
                console.log(movieSnapshot.getKey());
            }
        }
    }

    @Override
    public void onCancelled(FirebaseError firebaseError) {

    }
});

3
DataSnapshot ऑब्जेक्ट पर कोई getLead () विधि नहीं है।
पराग कदम

3
उन्होंने इसे मूवी ऑब्जेक्ट में बदल दिया और यह मानते हुए कि गेटलीड () मेथो है।
किम जी फाम

1
बहुत बहुत धन्यवाद। यह और अधिक काम कर रहा है जहां
क्लॉस

1

फ्रैंक का जवाब अच्छा है, लेकिन फायरस्टोर ने array-containsहाल ही में पेश किया जो कि करना और पूछताछ करना आसान बनाता है।

आप filtersफ़िल्टर जोड़ने के लिए एक फ़ील्ड बना सकते हैं । आप जितने की जरूरत है उतने मूल्य जोड़ सकते हैं। उदाहरण के लिए कॉमेडी और जैक निकोलसन द्वारा फ़िल्टर करने के लिए आप मान जोड़ सकते हैं comedy_Jack Nicholsonलेकिन अगर आप भी कॉमेडी और 2014 चाहते हैं तो आप comedy_2014अधिक फ़ील्ड बनाए बिना मान जोड़ सकते हैं ।

{
"movies": {
    "movie1": {
        "genre": "comedy",
        "name": "As good as it gets",
        "lead": "Jack Nicholson",
        "year": 2014,
        "filters": [
          "comedy_Jack Nicholson",
          "comedy_2014"
        ]
    }
  }  
}

1

Firebase कई शर्तों के साथ क्वेरी करने की अनुमति नहीं देता है। हालाँकि, मुझे इसके लिए एक रास्ता मिल गया:

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

                Query query = databaseReference.orderByChild("genre").equalTo("comedy");
                databaseReference.addValueEventListener(new ValueEventListener() {
                    @Override
                    public void onDataChange(@NonNull DataSnapshot dataSnapshot) {

                        ArrayList<Movie> movies = new ArrayList<>();
                        for (DataSnapshot dataSnapshot1 : dataSnapshot.getChildren()) {
                            String lead = dataSnapshot1.child("lead").getValue(String.class);
                            String genre = dataSnapshot1.child("genre").getValue(String.class);

                            movie = new Movie(lead, genre);

                            movies.add(movie);

                        }

                        filterResults(movies, "Jack Nicholson");

                        }

                    }

                    @Override
                    public void onCancelled(@NonNull DatabaseError databaseError) {

                    }
                });

एक बार जब हम डेटाबेस से प्रारंभिक फ़िल्टर्ड डेटा प्राप्त कर लेते हैं, तो हमें अपने बैकएंड में और फ़िल्टर करने की आवश्यकता होती है।

public void filterResults(final List<Movie> list,  final String genre) {
        List<Movie> movies = new ArrayList<>();
        movies = list.stream().filter(o -> o.getLead().equals(genre)).collect(Collectors.toList());
        System.out.println(movies);

        employees.forEach(movie -> System.out.println(movie.getFirstName()));
    }

-1
ref.orderByChild("lead").startAt("Jack Nicholson").endAt("Jack Nicholson").listner....

यह काम करेगा।

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