Adam Lee
Adam Lee

Reputation: 66

Firebase: How to retrieve two values for the same key query?

What I am trying to do is to query Firebase for two values with the same key. My database is like this:

"Document" : [ {
    "fileType" : "PDF",
    "language" : "en",
    "linkUrl" : "https://myfile.pdf",
    "name" : "Installation Guide"
  }, {
    "fileType" : "DOCUMENT",
    "language" : "fr",
    "linkUrl" : "https://myfile.txt",
    "name" : "text.txt"
  }

I have written a query in my Android project to retrieve all documents with the same language and it works.

val selectedLanguage = LocalStorageHelper.getInstance(this)?.getSelectedLanguage()
val docRef = rootRef.child("Document").orderByChild("language").equalTo("en")

But now what I would like to do is, look for "en" and "fr".

Is it possible to do like the above, I have searched online but didn't find anything positive on this.

Upvotes: 0

Views: 2005

Answers (4)

malliaridis
malliaridis

Reputation: 494

denormalization is a good practice in NoSQL databases. However, when doing it wrong, you have a lot of unnecessary and repetitive data. Denormalization is in normal cases a copy of your data, but not in the same format. The denormalized data should contain less or other content from which you get some benefits for specific use cases in your application. Some of these benefits are less unnecessary data download (since some data are not needed in that specific part of your application) and different search or filter algorithms.

With the example of @Alex Mamo you would create for any language combination a copy of your data. In cases where your user can e.g. choose multiple languages, you would have the same entry with all it's content more than twice in your database. This is normally not what you want. (Think about combinations of en/fr, en/de, en/fr/de, maybe en/gr too, and so on).

I would just use a flag and update the entries with the flag whenever the language selection changes. In that way, you could select documents with the flag prefLang = true and update (add or remove the flag) the documents whenever the languages change. In that way, the only data tha is written / modified is the flag information. Otherwise, when you create a special document just for your language preferences, you would copy and remove the whole document information.

Have also in mind your limitations of the node sizes. You should, as @Alex mentioned, use multiple document nodes instead of an array in a single node.

Upvotes: 0

Alex Mamo
Alex Mamo

Reputation: 138814

As @PeterHaddad mentioned in his answer, unfortunately there is no AND operator in Firebase. If you say that you cannot swith to Firestore where this is a simple operation, you need to know that we have a workaround that can help you achieve the same thing. So to solve this, you can create a compound node that can hold all the objects which have the language property set to en or fr. Your database structure should look like this:

Firebase-root
  |
  --- EnFrDocuments
  |      |
  |      --- documentId
  |      |     |
  |      |     --- fileType: "PDF"
  |      |     |
  |      |     --- language: "en"
  |      |     |
  |      |     --- linkUrl: "https://myfile.pdf"
  |      |     |
  |      |     --- name : "Installation Guide"
  |      |
  |      --- documentId
  |            |
  |            --- fileType: "DOCUMENT"
  |            |
  |            --- language: "fr"
  |            |
  |            --- linkUrl: "https://myfile.txt"
  |            |
  |            --- name : "myfile.txt"
  |
  --- Documents
        |
        --- //use the same structure

Structure which I recommend you to be used also to Document node rather then store those obects into an array.

This practice is called denormalization and is a common practice when it comes to Firebase. For a better understanding, I recommend you see this video, Denormalization is normal with the Firebase Database.

Also, when you are duplicating data, there is one thing that need to keep in mind. In the same way you are adding data, you need to maintain it. With other words, if you want to update/detele an item, you need to do it in every place that it exists.

Upvotes: 0

Joseph Webber
Joseph Webber

Reputation: 2173

Filter the languages on the client.

val docRef = rootRef.child("Document").orderByChild("language").on('value', function(snapshot) {
  val filteredDocuments = snapshot.val().filter(function(document) {
    return document.language === 'en' || document.language === 'fr';
  });
});

Upvotes: 0

Peter Haddad
Peter Haddad

Reputation: 80904

You cannot use the AND clause in firebase database, you are only able to query on one language, so you can only do:

orderByChild("language").equalTo("en")

Upvotes: 1

Related Questions