通过 .whereArrayContains() 查询时的意外行为 [英] Unexpected Behavior When Query by .whereArrayContains()

查看:25
本文介绍了通过 .whereArrayContains() 查询时的意外行为的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个 RecyclerView,它利用 FireaseUI 并通过时间戳"字段(按顺序)从轮询"节点订购所有对象.

新片段 - .onViewCreated()

 查询 queryStore = FirebaseFirestore.getInstance().collection(POLLS_LABEL).orderBy("时间戳", Query.Direction.ASCENDING);//Cloud Firestore 没有任何排序;必须实现时间戳以按顺序排序FirestoreRecyclerOptions<Poll>storeOptions = new FirestoreRecyclerOptions.Builder().setQuery(queryStore, Poll.class).建造();mFirestoreAdaper = new FirestoreRecyclerAdapter(storeOptions) {@覆盖protected void onBindViewHolder(@NonNull 最终 PollHolder 持有者,最终 int 位置,@NonNull 轮询模型) {holder.mPollQuestion.setText(model.getQuestion());String voteCount = String.valueOf(model.getVote_count());//TODO:调查数千人投票计数的格式holder.mVoteCount.setText(voteCount);毕加索.get().load(model.getImage_URL()).合身().into(holder.mPollImage);holder.mView.setOnClickListener(new View.OnClickListener() {@覆盖公共无效onClick(查看视图){Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);String recyclerPosition = getSnapshots().getSnapshot(position).getId();Log.v("Firestore ID", recyclerPosition);toClickedPoll.putExtra("POLL_ID", recyclerPosition);开始活动(toClickedPoll);}});}

我的应用程序中有另一个布局订阅了同一个节点,而是通过关注者"和时间戳"进行查询.:

以下片段 - .onViewCreated()

 查询 queryStore = FirebaseFirestore.getInstance().collection(POLLS_LABEL).whereArrayContains("追随者", mUserId).orderBy("时间戳", Query.Direction.ASCENDING);FirestoreRecyclerOptions<Poll>storeOptions = new FirestoreRecyclerOptions.Builder().setQuery(queryStore, Poll.class).建造();mFirestoreAdaper = new FirestoreRecyclerAdapter(storeOptions) {@覆盖protected void onBindViewHolder(@NonNull 最终 PollHolder 持有者,最终 int 位置,@NonNull 轮询模型) {holder.mPollQuestion.setText(model.getQuestion());String voteCount = String.valueOf(model.getVote_count());//TODO:调查数千人投票计数的格式holder.mVoteCount.setText(voteCount);毕加索.get().load(model.getImage_URL()).合身().into(holder.mPollImage);holder.mView.setOnClickListener(new View.OnClickListener() {@覆盖公共无效onClick(查看视图){Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);String recyclerPosition = getSnapshots().getSnapshot(position).getId();Log.v("Firestore ID", recyclerPosition);toClickedPoll.putExtra("POLL_ID", recyclerPosition);开始活动(toClickedPoll);}});}

在第一个场景中,当 UI 项添加到 Firebase 时,它​​们会实时填充到我的 RecyclerView 中.然而,当我通过.whereArrayContains"查询时,我没有得到同样的行为,我很好奇为什么.这些项目只会在我重新启动应用程序时重新出现:

我注释掉了以下行:

//.whereArrayContains("followers", mUserId)

并且行为按预期执行,因此我可以将问题隔离到 .whereArrayContains() 查询.这是每个 Fragment 之间的唯一区别.

解决方案

发生这种情况是因为当您同时使用 whereArrayContains()orderBy() 方法时查询,需要

I have a RecyclerView that utilizes the FireaseUI and orders all objects from the "Polls" node by the "timestamp" field (sequentially).

New Fragment - .onViewCreated()

 Query queryStore = FirebaseFirestore.getInstance()
            .collection(POLLS_LABEL)
            .orderBy("timestamp", Query.Direction.ASCENDING);
    //Cloud Firestore does not have any ordering; must implement a timestampe to order sequentially

    FirestoreRecyclerOptions<Poll> storeOptions = new FirestoreRecyclerOptions.Builder<Poll>()
            .setQuery(queryStore, Poll.class)
            .build();
    mFirestoreAdaper = new FirestoreRecyclerAdapter<Poll, PollHolder>(storeOptions) {
        @Override
        protected void onBindViewHolder(@NonNull final PollHolder holder, final int position, @NonNull Poll model) {
            holder.mPollQuestion.setText(model.getQuestion());
            String voteCount = String.valueOf(model.getVote_count());
            //TODO: Investigate formatting of vote count for thousands
            holder.mVoteCount.setText(voteCount);
            Picasso.get()
                    .load(model.getImage_URL())
                    .fit()
                    .into(holder.mPollImage);
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);
                    String recyclerPosition = getSnapshots().getSnapshot(position).getId();
                    Log.v("Firestore ID", recyclerPosition);
                    toClickedPoll.putExtra("POLL_ID", recyclerPosition);
                    startActivity(toClickedPoll);

                }
            });
        }

I have another layout in my app that subscribes to this same node, but instead queries by "followers" and then by "timestamp.:

Following Fragment - .onViewCreated()

  Query queryStore = FirebaseFirestore.getInstance()
            .collection(POLLS_LABEL)
            .whereArrayContains("followers", mUserId)
            .orderBy("timestamp", Query.Direction.ASCENDING);

    FirestoreRecyclerOptions<Poll> storeOptions = new FirestoreRecyclerOptions.Builder<Poll>()
            .setQuery(queryStore, Poll.class)
            .build();
    mFirestoreAdaper = new FirestoreRecyclerAdapter<Poll, PollHolder>(storeOptions) {
        @Override
        protected void onBindViewHolder(@NonNull final PollHolder holder, final int position, @NonNull Poll model) {
            holder.mPollQuestion.setText(model.getQuestion());
            String voteCount = String.valueOf(model.getVote_count());
            //TODO: Investigate formatting of vote count for thousands
            holder.mVoteCount.setText(voteCount);
            Picasso.get()
                    .load(model.getImage_URL())
                    .fit()
                    .into(holder.mPollImage);
            holder.mView.setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    Intent toClickedPoll = new Intent(getActivity(), PollHostActivity.class);
                    String recyclerPosition = getSnapshots().getSnapshot(position).getId();
                    Log.v("Firestore ID", recyclerPosition);
                    toClickedPoll.putExtra("POLL_ID", recyclerPosition);
                    startActivity(toClickedPoll);

                }
            });
        }

In the first scenario, UI items populate, in real-time, into my RecyclerView as they are added to Firebase. However, when I query by ".whereArrayContains," I do not get this same behavior, and I was curious as to why. The items only reappear when I restart the application:

Edit:

I commented out the below line:

// .whereArrayContains("followers", mUserId)

and the behavior performed as expected, therefore I can isolate the issue to the .whereArrayContains() query. It is the only difference between each Fragment.

解决方案

This is happening because when you are using whereArrayContains() and orderBy() methods in the same query, an index is required. To use one, go to your Firebase Console and create it manually or if you are using Android Studio, you'll find in your logcat a message that sounds like this:

W/Firestore: (0.6.6-dev) [Firestore]: Listen for Query(products where array array_contains YourItem order by timestamp) failed: Status{code=FAILED_PRECONDITION, description=The query requires an index. You can create it here: ...

You can simply click on that link or copy and paste the url into a web broswer and you index will be created automatically.

Why is this index needed?

As you probably noticed, queries in Cloud Firestore are very fast and this is because Firestore automatically creates an indexes for any fields you have in your document. When you need to order your items, a particular index is required that should be created as explained above. However, if you intend to create the index manually, please also select from the dropdown the corresponding Array contains option, as in the below image:

这篇关于通过 .whereArrayContains() 查询时的意外行为的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆