【问题标题】:Unable to filter query with multiple clauses using Firebase Realtime Database无法使用 Firebase 实时数据库过滤具有多个子句的查询
【发布时间】:2018-10-30 01:06:50
【问题描述】:

我在 Firebase UI 中使用 Firebase 实时数据库,但是我无法使用多个子句进行搜索。

我需要的是获取没有特定 ID 的用户。因为我已经按城市过滤它们,所以我需要用特定的 id 过滤这些。 我一直在尝试以多种方式解决它,但是它们都没有成功。

这是我的数据库

我无法使用该用户名将卡片呈现给用户。

public class SearchFragment extends android.support.v4.app.Fragment {


    private EditText mSearchField;
    private ImageButton mSearchBtn;
    private RecyclerView mResultList;
    private DatabaseReference mUserDatabase;

    public static SearchFragment newInstance() { return new SearchFragment();  }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_search, container, false);
        mSearchField = view.findViewById(R.id.search_field);
        mSearchBtn = view.findViewById(R.id.search_btn);

        mResultList = view.findViewById(R.id.result_list);
        mResultList.setHasFixedSize(true);
        mResultList.setLayoutManager(new LinearLayoutManager(mResultList.getContext()));

        mSearchBtn.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                String searchText = mSearchField.getText().toString();
                firebaseUserSearch(searchText);
                mSearchField.setText("");
            }
        });

        mUserDatabase = FirebaseDatabase.getInstance().getReference("usuarios");
        return view;
    }

    public void firebaseUserSearch(String searchText) {
        Toast.makeText(getContext(), "Buscando usuários", Toast.LENGTH_LONG).show();

        String searchTextLower = searchText.toLowerCase();

        final Query firebaseSearchQuery = mUserDatabase.orderByChild("city").startAt(searchTextLower).endAt(searchTextLower + "\uf8ff");

        firebaseSearchQuery.addChildEventListener(new ChildEventListener() {
            @Override
            public void onChildAdded(DataSnapshot dataSnapshot, String s) {
                GenericTypeIndicator<Map<String, String>> genericTypeIndicator = new GenericTypeIndicator<Map<String, String>>() {};
                Map<String, String> map = dataSnapshot.getValue(genericTypeIndicator );
                String username = map.get("username").toString();
                Log.d("oi", username);
                Log.d("olar", UserDetails.username);

                if(username != UserDetails.username) {
                    final FirebaseRecyclerOptions<User> options =
                            new FirebaseRecyclerOptions.Builder<User>()
                                    .setQuery(firebaseSearchQuery, User.class)
                                    .build();
                    bindAndBuildFirebaseUi(options);
                }
            }



    public void bindAndBuildFirebaseUi(FirebaseRecyclerOptions options) {
        final FirebaseRecyclerAdapter<User, UsersViewHolder> firebaseRecyclerAdapter = new FirebaseRecyclerAdapter<User, UsersViewHolder>(options) {
            @Override
            public UsersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
                View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_layout, parent, false);
                return new UsersViewHolder(v);
            }

            @Override
            protected void onBindViewHolder(final UsersViewHolder holder, int position, final User model) {
                holder.bind(model);
                Log.d("SearchFragment", "Binded the model");
                holder.itemView.setOnClickListener(new View.OnClickListener() {
                    @Override
                    public void onClick(View v) {
                        UserDetails.chatWithId = model.getUsername();
                        UserDetails.chatWith = model.getName();
                        startActivity(new Intent(getContext(), Chat.class));
                    }
                });
            }
        };
        firebaseRecyclerAdapter.startListening();
        mResultList.setAdapter(firebaseRecyclerAdapter);
    }
}

如您所见,我什至尝试再次通过数据库过滤它们,但是,Firebase ui 正在从选项中获取过滤器,这是第一个按城市过滤用户的查询。

有谁知道如何避免使用特定 id 呈现用户???

而且我也知道 Firebase 不允许使用多个 orderBy。

【问题讨论】:

  • 你的意思是那些没有身份证的人?
  • 基本上我需要拿一个没有 iam 过滤的 id 的。这就是为什么有 if(username != UserDetails.username) 。但是这种方法不起作用,因为 FirebaseUi 正在获取来自 Query firebaseSearchQuery 的数据。
  • 这对 Firebase 来说是个大问题,它不支持不相等的查询,但是你可以像这样使用 java smth:: for(Iterator&lt;Map.Entry&lt;String, String&gt;&gt; it = map.entrySet().iterator(); it.hasNext(); ) { Map.Entry&lt;String, String&gt; entry = it.next(); if(entry.getKey().equals("test")) { it.remove(); }
  • 这种方法的问题是 FirebaseUI 正在从 firebaseSearchQuery 获取数据,它忽略了我接下来要做什么
  • calvin 而不是username != UserDetails.username,只需从地图中删除当前用户,其他一切保持原样

标签: java android firebase firebase-realtime-database firebaseui


【解决方案1】:

不幸的是,Firebase RTDB doesn't support multiple where clauses。但是,如果您正确地对数据进行非规范化,则可以使用一个查询链接到数据库中的另一个 ref,并以这种方式有效地过滤数据。查看文档:https://github.com/firebase/FirebaseUI-Android/blob/master/database/README.md#using-firebaseui-with-indexed-data

附带说明一下,您真的不应该使用 RTDB 来存储实际数据,因为它不会扩展。它专为多人游戏或票务应用等的低延迟实时更新而设计。相反,我建议您查看Firestore,特别是如果这是一个新应用。

这是我在下面的评论中提到的 hack:

public class MyAdapter extends FirebaseRecyclerAdapter {
    private static final int TYPE_NORMAL = 0;
    private static final int TYPE_HIDDEN = 1;

    private final View mEmpty = new View(getContext());

    public MyAdapter(@NonNull FirestoreRecyclerOptions options) {
        super(options);
        mEmpty.setVisibility(View.GONE);
    }

    @Override
    public int getItemViewType(int position) {
        if (getItem(position).username.equals(UserDetails.username)) {
            return TYPE_HIDDEN;
        } else {
            return TYPE_NORMAL;
        }
    }

    @Override
    public UsersViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (viewType == TYPE_HIDDEN) {
            return new UsersViewHolder(mEmpty);
        }

        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.list_layout, parent, false);
        return new UsersViewHolder(v);
    }

    @Override
    protected void onBindViewHolder(final UsersViewHolder holder, int position, final User model) {
        if (getItemViewType(position) == TYPE_HIDDEN) return;

        holder.bind(model);
        Log.d("SearchFragment", "Binded the model");
        holder.itemView.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                UserDetails.chatWithId = model.getUsername();
                UserDetails.chatWith = model.getName();
                startActivity(new Intent(getContext(), Chat.class));
            }
        });
    }
}

【讨论】:

  • 是的,我意识到,但是,我需要尽快想出一个解决方案,我无法重做我所有的数据库。
  • 这是在生产中吗?
  • 是的,它是..这就是为什么我要问很多问题
  • 啊,那有点痛苦。我个人认为花点时间使用云函数来执行实时迁移会更好,但我确实想出了一个快速(且丑陋)的技巧。请参阅上面的更新答案。
  • 您的解决方案的问题是它忽略了我的 FirebaseSearch。 ` 最终查询 firebaseSearchQuery = mUserDatabase.orderByChild("city").startAt(searchTextLower).endAt(searchTextLower + "\uf8ff");`
猜你喜欢
  • 2020-06-02
  • 2018-09-14
  • 2018-01-25
  • 2015-04-20
  • 2018-08-04
  • 1970-01-01
  • 2018-06-10
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多