2

I want my app to read the data within all keys from Firebase Database.

Here is a snapshot of my Database snapshot of my Database.

The keys under app_name represent a user and all keys within the user key have some data within them. I need to be able to read the data from within each such user key except that of the user itself (as in reading all data except the data that I add). I obviously don't know the key of all users and also that list can be extended or minimized later. The only level I can access by using FirebaseDatabase.getInstance.getReference.child(string) is under the app name. Is there a way to read data within the keys inside each user key and display the content in the form of a List View or Recycler Adapter?

EDIT: Here are some of the things I have tried

public class FeedFragment extends Fragment {

//Firebase instance variables
private FirebaseDatabase mFirebaseDatabase;
private DatabaseReference mQuestionDatabaseReference;
private ChildEventListener mChildEventListener;
private FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();

Attempt 1:

FirebaseRecyclerAdapter mAdapter;
public FeedFragment() {
    //empty constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    mFirebaseDatabase = FirebaseDatabase.getInstance();
    mQuestionDatabaseReference = mFirebaseDatabase.getReference();

    // Inflate the layout for this fragment
    View rootView =  inflater.inflate(R.layout.fragment_feed, container, false);

    RecyclerView recycler = (RecyclerView) rootView.findViewById(R.id.feed_view_list);
    recycler.setHasFixedSize(false);
    recycler.setLayoutManager(new LinearLayoutManager(getActivity()));

    mAdapter = new FirebaseRecyclerAdapter<DataGetter, StatsViewHolder>(DataGetter.class, 0, StatsViewHolder.class, mQuestionDatabaseReference) {
        @Override
        public void populateViewHolder(FeedViewHolder viewHolder, DataGetter feedDisplay, int position) {
            int layout = getItemViewType(position);
            if (layout == R.layout.binary_feed) {
                viewHolder.setQuestionTextBin(textDisplay.getQuestionText());
                viewHolder.setbOption1(textDisplay.getOption1());
                viewHolder.setbOption2(textDisplay.getOption2());
            }
            else if (layout == R.layout.rating_feed) {
                viewHolder.setQuestionTextRat(textDisplay.getQuestionText());
            } 
            else {
                viewHolder.setQuestionTextMul(textDisplay.getQuestionText());
                viewHolder.setmOption1(textDisplay.getOption1());
                viewHolder.setmOption2(textDisplay.getOption2());
                viewHolder.setmOption3(textDisplay.getOption3());
                if (textDisplay.getNoOfOptions() >= 4) {
                    viewHolder.setmOption4(textDisplay.getOption4());
                }
                if (textDisplay.getNoOfOptions() == 5) {
                    viewHolder.setmOption5(textDisplay.getOption5());
                }
            }
        }

        @Override
        public int getItemViewType(int position)
        {
            int view;
            if(getItem(position).getQuestionType() == MainActivity.BINARY){
                view = R.layout.binary_feed;
            }
            else if(getItem(position).getQuestionType() == MainActivity.RATING) {
                view = R.layout.rating_feed;
            }
            else //if(getItem(position).getQuestionType() == MainActivity.MULTIPLE)
            {
                view = R.layout.multiple_feed;
            }
            return view;
        }
    };
    recycler.setAdapter(mAdapter);

    return rootView;
}

@Override
public void onDestroy()
{
    super.onDestroy();
    mAdapter.cleanup();
}

Attempt 2:

FirebaseIndexRecyclerAdapter mAdapter;

public FeedFragment() {
    // empty constructor
}

@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {

    mFirebaseDatabase = FirebaseDatabase.getInstance();
    mQuestionDatabaseReference = mFirebaseDatabase.getReference();

    // Inflate the layout for this fragment
    View rootView = inflater.inflate(R.layout.fragment_feed, container, false);

    RecyclerView recycler = (RecyclerView) rootView.findViewById(R.id.feed_view_list);
    recycler.setHasFixedSize(false);
    recycler.setLayoutManager(new LinearLayoutManager(getActivity()));

    //attempt -> from Firebase documentation, loop over all data
    final Query feedQuery = mQuestionDatabaseReference;

    ArrayList<DataSnapshot> feedListData = new ArrayList<DataSnapshot>();

    feedQuery.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            int i = 0;
            for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                ArrayList.add(postSnapshot);
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            // Getting Post failed, log a message
            Log.w(TAG, "loadPost:onCancelled", databaseError.toException());
            // ...
        }
    });

    mAdapter = new FirebaseIndexRecyclerAdapter<DataGetter, FeedViewHolder>(DataGetter.class, 0, FeedViewHolder.class,
            feedQuery,mQuestionDatabaseReference) {
            //remaining code is same as attempt 1
    }
M J Learner
  • 171
  • 2
  • 11
  • There is no way in the Firebase Database API to exclude specific nodes based on their value. See https://stackoverflow.com/a/39195551/209103 – Frank van Puffelen May 31 '17 at 13:59
  • oh, okay. Thank you for that @FrankvanPuffelen. But is there any way to accomplish the first part, that is to read all the data as explained in the question? – M J Learner May 31 '17 at 16:17
  • You can read from any location in the database. So if you want the keys for a specific user, you'd read `/app_home/$uid`. If you want to read all users, you'd read `/app_home` and then loop over the users. See https://firebase.google.com/docs/database/web/lists-of-data#listen_for_value_events – Frank van Puffelen May 31 '17 at 21:27
  • @FrankvanPuffelen 1)With the approach you suggested I somehow ended up reading the data keys instead of the data stored within those keys (eg- reading KI-7Xt1sXXDEAycabo5 instead of the value of option1). Could you possibly send some code to show how to actually perform the reading through a loop? 2)Just being curious. Is there a way to use `FirebaseIndexListAdapter` which is a part of FirebaseUI to accomplish the above? If yes, how do I initialise keyRef and dataRef? Refer to this:https://github.com/firebase/FirebaseUI-Android/tree/master/database. – M J Learner Jun 01 '17 at 07:30
  • That's not how Stack Overflow works. If you have code that doesn't do what you want it to do, share the minimal code that completely reproduces the problem. Such a so-called [MCVE](http://stackoverflow.com/help/mcve) (read the link, it's quite useful) is the best way to get help with coding problems. – Frank van Puffelen Jun 01 '17 at 09:14
  • @FrankvanPuffelen Oops, that was a bad mistake. Sorry, I'm new to this community. I have edited my question to include the code that I wrote. – M J Learner Jun 01 '17 at 12:16
  • Thanks for that. You have two approaches, each of which could be made to work. But neither of which will skip the current user's node; most developers work around this by hiding the view for the current user. What's the problem? It helps to have a *single* MCVE, so that we can understand what you're struggling with. – Frank van Puffelen Jun 01 '17 at 12:30
  • To explain the problem as I cannot really pin-point the part of the code that could suffice for an MCVE in this case, I'm guessing that either there should be something that I should correct within the `ValueEventListener` or the parameters that I am passing within `FirebaseIndexListAdapter`. Basically the part where I perform an action like `viewHolder.setQuestionTextBin(textDisplay.getQuestionText());`, I'm expecting that the data is being read from **within** a key like KI-7Xt1sXXDEAycabo5; instead I'm reading data from within a key like IW9CQ... (database pic above). @FrankvanPuffelen – M J Learner Jun 01 '17 at 15:26
  • The FirebaseUI adapters shows the list of child nodes that you pass to it. Since you pass the top-level `DatabaseReference`, your adapter will show (what seem to be) users: `IW9...`, MiS...`. You seem to think it will recursively show the nested nodes under that, but it doesn't. If you want to show the push IDs under that, you'll need to do so yourself in `populateView`. – Frank van Puffelen Jun 01 '17 at 15:47
  • @FrankvanPuffelen. Finally I understand what is going wrong. Although I don't know the correct method yet but thanks a lot. – M J Learner Jun 01 '17 at 16:42
  • 1
    In Firebase you model the data for what you want to show in your app. So if you want to show a list of something, model a list of those things in the database. If you need to show a list of users, store a list of users. If you need to show a list of questions, store a list of questions. – Frank van Puffelen Jun 01 '17 at 17:08

1 Answers1

1

In the above code, adding ValueAddedListener sets value within postSnapshot to keys like Ki-7Xt.. Adding another loop to iterate through postSnapshot.getChildren() will give the necessary "inner data".

//a custom adapter extended from ArrayAdapter
FeedAdapter feedAdapter;
feedQuery.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            int i = 0;
            for (DataSnapshot postSnapshot: dataSnapshot.getChildren()) {
                /*One way to exclude some data is to ignore it whenever it
                 *appears and take action for the others. The same approach 
                 *has been taken here in the if condition*/
                if(postSnapshot.getKey().compareTo(user.getUid())!=0) {
                    //The inner loop to read data from the final desired location
                    for (DataSnapshot data : postSnapshot.getChildren()) {
                        DataGetter dataGetter = data.getValue(DataGetter.class);
                        //adding incoming data to adapter
                        feedAdapter.add(dataGetter);
                    }
                }
            }
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {
            //Getting values failed
            Log.i(TAG, "loadPost:onCancelled", databaseError.toException());
            //...
        }
    });

Thanks @FrankvanPuffelen for the explanation you gave in your last 2 comments.

M J Learner
  • 171
  • 2
  • 11