ユーザーのコレクションがあり、データベースからすべてのユーザーにクエリを実行して、それらをRecyclerView
に1つを除いて表示しますmine。これは私のdbスキーマです:
users [collection]
- uid [document]
- uid: "fR5bih7SysccRu2Gu9990TeSSyg2"
- username: "John"
- age: 22
- //other users
そのようにデータベースをクエリする方法:
String uid = FirebaseAuth.getInstance().getCurrentUser().getUid();
Query q = db.collection("users").whereNotEqualTo("uid", uid);
したがって、FirestoreRecyclerOptions
内の他のすべてのユーザーを表示するには、このクエリオブジェクトをRecyclerView
オブジェクトに渡す必要があります。
これは可能ですか?そうでない場合、どうすればこれを解決できますか?ありがとう!
編集:
options = new FirestoreRecyclerOptions.Builder<UserModel>()
.setQuery(query, new SnapshotParser<UserModel>() {
@NonNull
@Override
public UserModel parseSnapshot(@NonNull DocumentSnapshot snapshot) {
UserModel userModel = documentSnapshot.toObject(UserModel.class);
if (!userModel.getUid().equals(uid)) {
return userModel;
} else {
return new UserModel();
}
}
}).build();
何日もこの問題に取り組んできた後、ようやく答えを見つけました。 @Rajの助けがなければ、私はこれを解決できませんでした。忍耐とガイダンスをありがとう@Raj.
まず最初に、これからの回答で@Frank van Puffelenが提供した回答 post によると、2つのクエリを1つのアダプタに渡すのに役立つソリューションの検索をやめました。
この質問で私が達成したかったのは、データベースをクエリして、1人を除くすべてのユーザーを取得することだけでした。したがって、2つのクエリを1つのインスタンスに結合できないため、両方のクエリの結果を結合できることがわかりました。だから私は2つのクエリを作成しました:
_FirebaseFirestore db = FirebaseFirestore.getInstance();
Query firstQuery = db.collection("users").whereLessThan("uid", uid);
Query secondQuery = db.collection("users").whereGreaterThan("uid", uid);
_
ユーザーオブジェクトにUserModel
(POJO)クラスがあります。 1つではないが見つかりましたが、2つの問題を解決する方法が見つかりました。 1つ目は、データベースにクエリを実行して、最初の基準に対応するすべてのユーザーオブジェクトを取得し、それらをリストに追加することです。その後、データベースを再度クエリし、2番目の基準に対応する他のユーザーオブジェクトを取得して、sameリストに追加します。これで、必要なすべてのユーザー(1つはクエリからの特定のIDを持つユーザー)を含むリストが作成されました。これは将来の訪問者のためのコードです:
_firstQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
List<UserModel> list = new ArrayList<>();
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
UserModel userModel = document.toObject(UserModel.class);
list.add(userModel);
}
secondQuery.get().addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (DocumentSnapshot document : task.getResult()) {
UserModel userModel = document.toObject(UserModel.class);
list.add(userModel);
}
//Use the list of users
}
}
});
}
}
});
_
2番目のアプローチは、次のようにTasks.whenAllSuccess()
を使用するため、はるかに短くなります。
_Task firstTask = firstQuery.get();
Task secondTask = secondQuery.get();
Task combinedTask = Tasks.whenAllSuccess(firstTask, secondTask).addOnSuccessListener(new OnSuccessListener<List<Object>>() {
@Override
public void onSuccess(List<Object> list) {
//This is the list that I wanted
}
});
_
Firestoreはnot equal to
操作をサポートしていません。したがって、クライアント側でデータをフィルタリングする必要があります。あなたの場合、あなたは1つの余分なアイテムしか持っていないので、あなたはそれを取り除くことができます。
そのため、リサイクラーアダプターデータレイヤーにデータを追加するときに、!=
条件に一致するデータを制限する独自のリサイクラー実装を構築する必要がある場合があります。
提供されているリサイクラー実装firebaseについては調べていませんので、アダプターデータへのデータ操作をサポートしているかどうかはわかりません。
以下に、リサイクラービューの実装を開始するための適切なリソースを示します。 https://www.androidhive.info/2016/01/Android-working-with-recycler-view/
公式のファイヤーストアのドキュメントによると:-
Cloud Firestoreは、次のタイプのクエリをサポートしていません。
!=句を使用したクエリ。この場合、クエリを大なりクエリと小なりクエリに分割する必要があります。たとえば、クエリ句where( "age"、 "!="、 "30")はサポートされていませんが、where( "age"、 "<句を含むクエリを2つ組み合わせることで、同じ結果セットを取得できます。 "、" 30 ")とwhere(" age "、"> "、30)という句を含むもの。
FirestoreRecyclerAdapterを使用している場合、FirestoreRecyclerOptionsはsetQuery()メソッドを使用してクエリを直接受け入れるため、クライアント側のフィルタリングを実行できません。
リサイクラービューでアイテムが空になる可能性のあるデータを設定しているときにonBindViewHolder()でフィルターを適用しようとした場合。これを解決するには、方法2を参照してください。
したがって、問題の解決策として考えられるのは、すべてのドキュメントの下のユーザーコレクションに整数フィールドを作成することです。例えば:-
users [collection]
- uid [document]
- uid: "fR5bih7SysccRu2Gu9990TeSSyg2"
- username: "John"
- age: 22
- check: 100
これで、値が100の「check」変数を作成しました。したがって、他のすべてのドキュメントに「check」の値を100未満に設定します。これで、check <100のドキュメントを検索するクエリを簡単に作成できます:-
Query q = db.collection("users").whereLessThan("check", 100);
これにより、不要なドキュメントを除くすべてのドキュメントが取得されます。また、データを設定するときに、チェック変数をスキップして他のパラメーターを設定できます。
方法2(クライアント側のフィルタリング)
OnBindViewHolder()メソッドでチェックを適用して、取得したuidが現在のユーザーuidと一致する場合、Recyclerビューの高さを0dpに設定できます。なので:-
ViewUserAdapter.Java
public class ViewUserAdapter extends FirestoreRecyclerAdapter<User, ViewUserAdapter.ViewUserHolder>
{
String uid;
FirebaseAuth auth;
public ViewUserAdapter(@NonNull FirestoreRecyclerOptions<User> options)
{
super(options);
auth = FirebaseAuth.getInstance();
uid = auth.getCurrentUser().getUid();
}
@Override
protected void onBindViewHolder(@NonNull ViewUserHolder holder, int position, @NonNull User model)
{
DocumentSnapshot snapshot = getSnapshots().getSnapshot(position);
String id = snapshot.getId();
if(uid.equals(id))
{
RecyclerView.LayoutParams param = (RecyclerView.LayoutParams)holder.itemView.getLayoutParams();
param.height = 0;
param.width = LinearLayout.LayoutParams.MATCH_PARENT;
holder.itemView.setVisibility(View.VISIBLE);
}
else
{
holder.tvName.setText(model.name);
holder.tvEmail.setText(model.email);
holder.tvAge.setText(String.valueOf(model.age));
}
}
}
最も簡単な解決策は、PagedListAdapterを使用してカスタムDataSourceを作成することです。 Firestoreクエリ用。 DataSourceでは、Queryを配列またはArrayListに変換できますメソッドcallback.onResult(...)
にデータを追加する前に、アイテムを簡単に削除できます。
同様のソリューションを使用して、Firestoreクエリの後でデータを処理し、時間属性でフィルターして並べ替え、クライアントの品質スコア属性で再度並べ替えてから、データをcallback.onResult(...)
に返しました。 。
class ContentFeedDataSource() : ItemKeyedDataSource<Date, Content>() {
override fun loadBefore(params: LoadParams<Date>, callback: LoadCallback<Content>) {}
override fun getKey(item: Content) = item.timestamp
override fun loadInitial(params: LoadInitialParams<Date>, callback: LoadInitialCallback<Content>) {
FirestoreCollections.contentCollection
.collection(FirestoreCollections.ALL_COLLECTION)
.orderBy(Constants.TIMESTAMP, Query.Direction.DESCENDING)
.whereGreaterThanOrEqualTo(Constants.TIMESTAMP, DateAndTime.getTimeframe(WEEK))
.limit(params.requestedLoadSize.toLong())
.get().addOnCompleteListener {
val items = arrayListOf<Content?>()
for (document in it.result.documents) {
val content = document.toObject(Content::class.Java)
items.add(content)
}
callback.onResult(items.sortedByDescending { it?.qualityScore })
}
}
override fun loadAfter(params: LoadParams<Date>, callback: LoadCallback<Content>) {
FirestoreCollections.contentCollection
.collection(FirestoreCollections.ALL_COLLECTION)
.orderBy(Constants.TIMESTAMP, Query.Direction.DESCENDING)
.startAt(params.key)
.whereGreaterThanOrEqualTo(Constants.TIMESTAMP, DateAndTime.getTimeframe(WEEK))
.limit(params.requestedLoadSize.toLong())
.get().addOnCompleteListener {
val items = arrayListOf<Content?>()
for (document in it.result.documents) {
val content = document.toObject(Content::class.Java)
items.add(content)
}
val sortedByQualityScore = ArrayList(items.sortedByDescending { it?.qualityScore })
callback.onResult(sortedByQualityScore)
sortedByQualityScore.clear()
}
}
}
よりシンプルで以前のクライアント側フィルタリング(リストにアイテムを追加する場合):
このようにすると、クライアント側で「等しくない」メソッドを使用して、Firestoreの問題に陥ることがなくなります。別の利点は、アダプターをいじったり、リサイクラーに必要のないリスト項目からビューを非表示にする必要がないことです。
public void getUsers(final ArrayList<Users> usersArrayList, final Adapter adapter) {
CollectionReference usersCollectionRef = db.collection("users");
Query query = usersCollectionRef
.whereEqualTo("is_onboarded", true);
query.get()
.addOnCompleteListener(new OnCompleteListener<QuerySnapshot>() {
@Override
public void onComplete(@NonNull Task<QuerySnapshot> task) {
if (task.isSuccessful()) {
for (QueryDocumentSnapshot document : task.getResult()) {
final String otherUserID = document.getId();
FirebaseUser user = mAuth.getCurrentUser();
String currentUserID = user.getUid();
if (!otherUserID.equals(currentUserId)) {
usersArrayList.add(new User(otherUserID));
adapter.notifyDataSetChanged(); //Ensures users are visible immediately
}
} else {
Log.d(TAG, "get failed with ", task.getException());
}
}
});
}
}
} else {
Log.d(TAG, "Error getting documents: ", task.getException());
}
}
});
}