I have a simple Database structure, I want to do a query on it :
get the article wherein motcle contains.(key), and from the articles found we order them by the highest note.
I know that to do the "AND" I have to make a nested query. but how can I get the first node the article when I am in the second node motcle.
the Database
Did you consider changing the way data is structured, e.g. storing "html" is your case as value istead of key? (or migrate to Firestore, which provides better querying capabilities)
Then you could do query similar to
ref("article").child(id)
.orderByChild("motocle/someKey")
.equalTo("Html")
This is typical approach with Firebase, when data is structured based on query you need.
Related
is there any way to get documents from firebase by list of IDs?
I have this list:
val IDs= listOf("id1","id2","id3","id4")
and I want to get all those documents without looping through them.
something like this, if possible:
Firebase.firestore.collection("users").documents(IDs).get()
The Firestore client libraries don't have the notion of batch reads which would allow to retrieve a set of documents given it's ids. Nonetheless, you can still make queries that filter on the document id by using the FieldPath.documentId() object. This value translates to a special sentinel that allows queries on the document id so you can write a query like below:
Firebase.firestore.collection("users")
.whereIn(FieldPath.documentId(), listOf("id1", "id2", [...], "id10"))
There's one restriction to note with this approach. The whereIn filter accepts at most 10 values. If you need to retrieve more it would be necessary to make several queries.
Alternatively, the approach suggested by Brettski of making a bunch of single document reads would work too.
That isn't possible in Firestore. Id's can only be accessed directly through a collection/document request.
I don't know Kotlin, though in JavaScript I would perhaps approach it by creating an array of functions for each of the documents, then using a Promise.all() to retrieve them at once. It is, imo a downside of Firestore where you can't query for multiple Id's.
In my chat application, I store the participants of a chat as their UIDs in a Map so I can so I can do queries like this:
.whereEqualTo("participantUIDs.$currentUserUid", true)
.whereEqualTo("participantUIDs.$partnerUid", true)
The problem is when I try to use this with orderBy
.whereEqualTo("participantUIDs.$currentUserUid", true)
.orderBy("lastMessageSentTimestamp")
I have to create a custom index. But this index will contain that specific user UID and I can't create an index for every user in my app. How can I circumvent this problem?
You can order the documents on the client after an unordered query. This should not be very taxing on the client app when the number of documents is less than 10,000.
Regarding:
I can't create an index for every user in my app.
That's definitely not an option, as there are some limitations when it comes to Cloud Firestore indexes:
https://firebase.google.com/docs/firestore/quotas#indexes
However, even if you manage to stay below these limits, that's not an option to manually create an index for each and every user that joins your app.
In my opinion, for your particular use-case, you should consider augmenting your data structure to allow a reverse lookup. Meaning that you should create a participantUIDs collection where you should keep the lists for each user. This technique is called denormalization and is a common practice when it comes to NoSQL databases like Cloud Firestore or Firebase Realtime Database.
But remember, there is "no perfect database structure":
What is the correct way to structure this kind of data in Firestore?
It's a little old, but I think this video might also help:
https://www.youtube.com/watch?v=u3KwKQddPoo
More info regarding why you need an index:
Why does this firestore query require an index?
P.S. You can also rely on Firebase Realtime Database when Cloud Firestore may become a little expensive. Both work really well together.
Info:
Array or Subcollection for storing events user uploaded
I have an App where there are Documents for each car. I somehow need to query the Documents in a Collection to give me the ones where a User has worked on some Tasks.
The Problem is however, the Fieldpath in each Document is different so I cant query with a static Fieldpath.
Here is the Example Structure of an Document, and yes I know it is one of the worst ways to do it but I already made it a long time ago.
So what would be the best way to get the worker Array Queried if the FieldPath is not static?
The Problem is however, the Fieldpath in each Document is different so I cant query with a static Fieldpath.
If you don't know the full path of a field value to query, you simply can't query it. There are no wildcards for document fields in a query. It sounds like you will have to change your document structure if you want to perform the query, or at least just duplicate some data into another field that lets you make the query you want. Duplicating data to satisfy queries is common in NoSQL type databases.
FirebaseUI-Android provides for indexed queries when using a FirebaseRecyclerAdapter. That works well when accessing Firebase Realtime DB data as explained here: https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md#using-firebaseui-with-indexed-data
But what about accessing Firestore data? It seems that FirestoreRecyclerAdapter does not support indexed queries via setIndexedQuery(keyref, dataref, ...) How can I maybe execute the data query manually inside the RecyclerView?
UPDATE: several people have claimed that Firestore doesn't need indexed queries anymore due to the build-in indexing with makes the schema design much easier than it was with Firebase Realtime DB. Well, I disagree.
Lets say I have a bunch of related items and transactions which I want to query by item and by transaction.
I can't make the transactions a subcollection of items as this would make it impossible to retrieve a list of all transactions. I also can't replicate the item data as redundant fields in each transaction since the data is mutable.
Given these constrains I am stuck with making items and transactions two independent collections which need to be combined again inside the app:
items: {
"item1": {
"name": "some editable label",
[more fields]
}
transactions: {
"trans1": {
"itemid": "item1"
[more fields]
}
"trans2": {
"itemid": "item1"
[more fields]
}
}
FirebaseRecyclerAdapter.setIndexedQuery would have allowed me to retrieve a list of transactions (key) and the corresponding item record with each transaction (data). Firestore indexing, while powerful, does not help in this situation.
There is no setIndexedQuery() method beneath FirestoreRecyclerOptions class because there is no need for a such a method. From the offical documentation regarding indexes,
Cloud Firestore requires an index for every query, to ensure the best performance. All document fields are automatically indexed, so queries that only use equality clauses don't need additional indexes.
If you need a query that is using more than one propoerty, you need to manually create a new index from the Firebase console. To create an index programmatically is not supported yet by Firestore.
Edit:
I can't make the transactions a subcollection of items as this would make it impossible to retrieve a list of all transactions.
That's correct, there are no collections beneath collections or documents beneath documents. But you can use the follwing structure:
Collection -> Document -> Collection
But remember, using nested collections and documents it's now a common practice in Firestore. Let asume you have transactions beneath items. In the Firebase Realtime Database, if you had a object nested within another object, every time you would have wanted to query your database to display only the items, the enitire Items object would have downloaded together with the Transactions object, ending to spend more bandwith. But when it comes to Collections and Documents that's not the case anymore.
I don't understand the use case of your app because there because there is less information but there is much easier in Cloud Firestore to create relations between collections and documents. If you have time, you can take a look on one of my tutorials on how to create a Firestore database structure.
Even if you are using Firebase Realtime database or Cloud Firestore database, denormalization is normal. So don't be afraid to duplicate data.
All of the Firestore data retrieval examples show a full document getting returned. Examples like this:
// Create a reference to the cities collection
CollectionReference citiesRef = db.collection("cities");
// Create a query against the collection.
Query query = citiesRef.whereEqualTo("state", "CA");
My database has 3,000 city objects in it, and I need to get a list of all the unique states in my database. Can someone show me an example of how I can get this information from Firestore? I'm hoping I don't need to download all 3000 documents just to collate this list myself.
You could create a Cloud Function which is triggered by an onWrite event to your cities collection. This function could see if the state already exists in a states collection and, if not, add it.
This way, you'll end up with a states collection which only has one of each state in it. As states are generally a 2 letter code, you could use this code as the document index, to ensure uniqueness in your cloud function writes.
As Frank says, the only way in which you can achieve this is by duplicationg data. This tehnique is named denormalization and for that I'll share you another resourse, which is a tutorial that I personally recomend you to see for a better understanding, Denormalization is normal with the Firebase Database. This tutorial was made for Firebase Realtime database but the same principles are also in Cloud Firestore.
So to solve your problem, you need to create another top level collection in which you need to store only the unique states. But you need to be aware of the fact that every time you add or delete a document, you need to do it twice, once for the cities collection that you already have and second for the newly created collection uniqueStates.