问题
I have a collection called creditcards
and a collection called ownedcreditcards
in Cloud Firestore. I want to perform a query where I JOIN the two collections to find only the creditcards that exists in the creditcards
-collection, and not in the ownedcreditcards
. From my understanding SQL like JOINS does not exist in Firestore, and you have to retrieve the data in multiple queries. I am trying to call the getAll()
-functions (which retrieves all the documents) on both my collections, temporarily store the data in two ArrayLists
, and then compare the two lists with each other. But my attempts of storing the data in an ArrayList
has been unsuccessful, as it returns empty when I try to LOG
it.
How can I store the data from both my collections in an ArrayList
, or is there an easier way of doing this?
creditcards-collection with the following fields:
- id
- name
- provider
ownedcreditcards-collection with the following fields:
- id
- creditcardid
- creditcardname
- nickname
- userid
The code for my Activity
and Store
-classes are more or less identical for both usercreditcard
and creditcard
. Below is the code for the usercreditcard
.
UserCreditCardActivity.kt
val arrayList = ArrayList<Any>()
private fun retrieveCards() {
val userCreditcard = UserCardStore()
userCreditcard.getAll(object : Callback<UserCardModel> {
override fun onCallback(list: List<UserCardModel>) {
for (card in list) {
adapter.add(UserCardItem(card)) //this works
arrayList.add(card) //this doesnt work as when I print the list it returns empty
}
}
})
}
UserCardStore.kt
override fun getAll(myCallback: Callback<UserCardModel>) {
auth = FirebaseAuth.getInstance()
documentdata.whereIn("userid", listOf(auth.uid))
.get().addOnCompleteListener { task ->
if (task.isSuccessful) {
val list = ArrayList<UserCardModel>()
for (document in task.result!!) {
val usercard = document.toObject(UserCardModel::class.java)
list.add(usercard)
}
myCallback.onCallback(list)
}
}
}
回答1:
From my understanding SQL like JOINS does not exist in Firestore, and you have to retrieve the data in multiple queries.
Yes, that's correct, a "JOIN" type operation is not supported by Cloud Firestore. A Firestore query can only get documents from a single collection at a time. If you need to get data from both collections and add the results to a list, you'll have to perform two different queries.
The key to solving this problem is to attempt to get the results of the second query only when the first query completes. In code, these queries should look like this:
creditcardsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
List<UserCardModel> userCardList = new ArrayList<>();
for (QueryDocumentSnapshot document : task.getResult()) {
userCardList.add(document.toObject(UserCardModel.class));
ownedcreditcardsRef.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot doc : task.getResult()) {
userCardList.add(doc.toObject(UserCardModel.class));
}
//Do what you need to do with the list
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
However, this approach might be considered a little bit expensive since you always read the content of both collections. A possible alternative you have is to introduce a third collection with data already "joined" from both collections. 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. It's for Firebase Realtime Database, but the same rules apply to Cloud Firestore.
来源:https://stackoverflow.com/questions/63632614/sql-like-joins-in-firestore