问题
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 Activityand 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