0

Basically my problem is that I had stored in firebase db a list of users with multiple attributes, some of them were private informations so I wanted to deny access to them. Rules aren't the answer because they can't be used as filters.

My solution was to create two new attributes for "users": "pvt" (private) and "pb" (public) and to store inside of them the correct attributes.

To create new users I used first:

mDatabase.child("users").child(prefs.getString("id firebase", " ")).child("public").setValue(newUserPublic);
mDatabase.child("users").child(prefs.getString("id firebase", " ")).child("private").setValue(newUserPrivate);

where newUserPublic and newUserPrivate are objects of simple custom classes that offers getters and setters for user's attributes (one for public and the other for private informations).

My final goal was to create a leaderboard that uses only public attributes of each user but I wadn't able to create a proper ListAdapter with this configuration.

My final try was to create a new class called User

public class User {

public UserDataPrivate getPvt() {
    return pvt;
}

public void setPvt(UserDataPrivate pvt) {
    this.pvt = pvt;
}

public UserDataPublic getPb() {
    return pb;
}

public void setPb(UserDataPublic pb) {
    this.pb = pb;
}

private UserDataPrivate pvt;

private UserDataPublic pb;

public void setId(String id) {
    this.id = id;
}

private String id;

public User(String id, UserDataPublic pb, UserDataPrivate pvt){
    this.pvt=pvt;
    this.pb=pb;
    this.id=id;
}

}

to create new user with:

User user = new User(newUserPublic, newUserPrivate);
mDatabase.child("users").child(prefs.getString("id firebase", " ")).setValue(user);

and the current adapter is

DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
    Query query = mDatabase.child("pb").orderByChild("points");
    ListAdapter adapter = new CustomFirebaseAdapter<User>(this, User.class, R.layout.list_item, query) {
        @Override
        protected void populateView(View v, User model, int position) {
            //code that uses model.getPb()
        }
    };

but it doesn't work (//code is never executed).

Do you have any idea how I can solve this?

This is a test user in Firebase:

IMG

EDIT: Tried to user pb/score inside the query but it crashes. I think the problem is that firebase can't handle complex objects or I'm missing something. I have other code portions wich retrive single user data so I use

final DatabaseReference userDatabase = mDatabase.child("users").child(prefs.getString("id firebase", " "));

    userDatabase.addValueEventListener(new ValueEventListener() {
        @Override
        public void onDataChange(DataSnapshot dataSnapshot) {
            User user = dataSnapshot.getValue(User.class);
            //...
        }

        @Override
        public void onCancelled(DatabaseError databaseError) {

        }
    });

and it crashes when setting user. I thought that if I save users in my db using user objects I could retrive them in the same way but I'm probably wrong.

Korr4K
  • 15
  • 6

3 Answers3

1

When you call orderByChild() on a location, Firebase takes each node directly under that location and orders it on the child you specify. Since you call orderByChild("points") on /users, it takes the nodes under /users and orders them on their (non-existing) points property.

To order each user on their pb/points property, use that path in the call to orderByChild(). So:

DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
Query query = mDatabase.orderByChild("pb/points");
ListAdapter adapter = new CustomFirebaseAdapter<User>(this, User.class, R.layout.list_item, query) {
    @Override
    protected void populateView(View v, User model, int position) {
        //code that uses model.getPb()
    }
};
Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
  • App is crashing! I think firebase can't handle complex objects. I edit my first post to post some code – Korr4K Apr 12 '17 at 06:29
  • If it crashes, include the logcat of the stacktrace in your post. – Frank van Puffelen Apr 12 '17 at 07:24
  • You saved me! User class has not a constructor with 0 parameters, for reasons that I don't know it is required by dataSnapshopt.getValue(). Now it is working – Korr4K Apr 12 '17 at 08:11
0

This code:

DatabaseReference mDatabase = FirebaseDatabase.getInstance().getReference("users");
Query query = mDatabase.child("pb").orderByChild("points");

will point to /users/pb and order by users/pb/??/points. If you seek for query that point to /users/?? order by users/??/pb/points, then I think Firebase can't do that for now. Check this post

Community
  • 1
  • 1
koceeng
  • 2,169
  • 3
  • 16
  • 37
  • 1
    The first link in my answer actually points to the solution for this question. Since `pb/points` is at a fixed path, it can be queried with `orderByChild("pb/points")`. – Frank van Puffelen Apr 12 '17 at 05:50
0

You can use a firebase listview adapter and that does a lot of the work for you. But you might want to change your user objects.

Query query = FirebaseDatabase.getInstance().getReference("users").orderByChild("pb/points");

FirebaseListAdapter adapter = new FirebaseListAdapter(activity, User.class, R.id.modelLayout, query) {
        @Override
        protected void populateView(View view, User user, int i) {
            //view is current view
            //user is current user
            //i is position
            TextView points = view.findViewById(R.id.pointsTextView);
            String userPoints = user.getPb().getPoints();

            points.setText(userPoints);
        }
    };

Then apply the adapter on a view

listview.setAdapter(adapter);
Haider Malik
  • 1,581
  • 1
  • 20
  • 23