Ok, so in this scenario we have three users that download my app: Mike, Suzy, and John. I want to store an Entity object on the Datastore using this code, for each user:
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Entity e = new Entity("Person",someKey);
e.setProperty("name",name);
e.setProperty("age",age);
ds.put(e);
So when the three users named above use my app for the first time, my Google Cloud Datastore shows three entities of kind, "Person" with name properties: "Mike", "Suzy", and "John", and the cooresponding age properties.
Lets say that John opens the app and wants to see who else is using the app, how can I get those entities and display them to john so that he sees Suzy and Mike's names?
Basically, I want to be able to share data between all users by storing entities on the Datastore, and granting access to other users' entities to every user.
Another scenario could be an implementation of a High Scores list: Let's say I only want to keep the top 5 all time high scores across all users:
Entity e2 = new Entity("HiScore",aKey);
e.setProperty("score",score);
ds.put(e);
So when a user gets a new score, I would pull all existing entities, check the score properties on all of them and update the datastore accordingly by replacing a score. At the same time, I'd also want this data update pushed to other devices.
So here are two general examples along the lines of what I would like to accomplish (I know about google-play API that handles high scores for you, so don't tell me to use that because I'm not necessarily trying to implement high scores). In short I want to create a feed of the current entities that exist on my Datastore that can be seen by all users
Is using datastore entities the right way to go for this?
This is a very broad question (or set of questions), but to answer some of your individual points:
Lets say that John opens the app and wants to see who else is using the app, how can I get those entities and display them to john so that he sees Suzy and Mike's names?
That's a very simple query, like this:
DatastoreService ds = DatastoreServiceFactory.getDatastoreService();
Query q = new Query("Person");
List<Entity> persons = ds.prepare(q).asList(FetchOptions.Builder.withDefaults());
You then say
I want to be able to share data between all users by storing entities on the Datastore, and granting access to other users' entities to every user
Users don't own entities; your Cloud Platform project owns entities. So it's up to your application to determine who can see what data. There's nothing inherent in Datastore preventing Suzy from seeing Mike's Person entity unless your application puts rules in place.
Finally,
Another scenario could be an implementation of a High Scores list: Let's say I only want to keep the top 5 all time high scores across all users...
... So when a user gets a new score, I would pull all existing entities, check the score properties on all of them and update the datastore accordingly by replacing a score.
Depending on your traffic you may find that solution doesn't scale well; I would recommend reading this case study.
Related
My idea is to create a like&unlike system for posts (a user can like and unlike a post) and to show a list of users in a fragment, ordered this way: the top user is the one for which there are the most numerous likes.
In my Firebase Firestore database:
I have a collection of posts. Each document (which is a post) contains the ID of the user that created it, and a counter of likes (I call it "A").
I have another collection, of users. Each document (which is a user) contains a counter (I call it "B") that counts for the number of likes, all posts combined.
For the moment, I use "B" to order the users in the list of users I've described above. I use "B" this way: return FirebaseFirestore.getInstance().collection("users").orderBy("likes", Query.Direction.DESCENDING);.
However, due to some technical facts in relation to Firebase Security Rules, and to simplify the database structure, I would want to only use "A", and remove "B". More precisely, I would want to get all the users, and order them according to "A". However, the counter "A" is defined in the documents of the collection of posts, whereas the counter "B" was defined in the documents of the collection of users: that makes it easier to use.
So my question is: for each user, I would have to get all their posts, then sum up their counter "A", then get all the users, then order them according to this sum. However, I would want to know: is it possible to do this using Firebase Firestore Android API? (something like the instruction given before) In others words: How to order documents from a collection, according to the field of documents of another collection? But note that in fact it's more difficult, since I must sum up the counter "A" of each post created by the user.
What you're trying to do is essentially a "join" type operation, which is not supported by Firestore. A Firestore query can only consider documents in a single collection at a time. If you have data from two collections to use for the purpose of generating query results, you will have at least two queries to perform.
The only real alternative you have is to introduce a third collection with data already merged from the other two collections that supports the query you want to make. This is common in NoSQL type databases, and is called "denormalization".
I have two different types of users Teachers and Students . I use Firebase Auth with Email and password to Authenticate them and store them in the Firebase Real time database . My question is is there a way to create custom accesor methods such as getCurrentUser().getEmail, getDisplayname etc . I need to display different UI for different user type (Teacher/Student) from the current user-type
You got 2 type of users. So first of all, you can make only one firebase structure for both user and just add a boolean variable TEACHER that indicates if a user is a teacher or a student.
But what I usually do is to seperate the users in two different firebase structures meaning that you should create a firebase path teacher/user_id and an another student/user_id which will give you flexibility with retreiving data and display the data in different UI.
I recently started to learn Android and I came across a problem. I want to create a code for Firebase (the database I am using to store values) such that the contents from one set are matched to elements in another set.
The scenario is as follows: there is a student who wants to learn or is interested in learning a new skill (C/C++, drawing, music, etc.), if he were to update them in their profile, he should get suggestions as names of other users registered in the application who have already listed their skill set.
It is much like how Facebook suggests common friends, but here, the basis for suggestion is what skills the user has and what he wants to learn.
I worked on the same thing for one of my apps. I'll write about what I did to achieve that
First of all, you need to design your Realtime Database structure in a way to achieve that.
Example of a Individual User node in your database at firebase could be like
User
- Personal Details
- First name
- last name
- Dob
- Interests (values like "music,movies,sports") //Separated by a comma
- ...
Now lets say User A likes "music" and that you need to suggest him other users who likes music too, In this case what you can do is retrieve all the users who have interests "music" in their profile.
reference.addChildEventListener()
In here,inside the onChildAdded() you can compare to see if the Interest of a particular user has music in it. (if it does, add that user to your arraylist for your recyclerview to display it.)
Hope it helps!
I'm developing an Android app that uses the Parse.com online database, and i'm having some difficulty wrapping my head around the relationship between classes.
I have the following classes defined: User (default), PrivateInfo, Relationships.
The relationships class is a many-to-many class between users (users stored as pointers), and the PrivateInfo class contains information specific to a user (stored as a pointer) to be accessed only by said user or users present in a relationship. For example, if user A is in a relationship with user B, then A should be able to access this privateInfo.
I have an activity where the private info from all users is to be shown. How can I build a query that will fetch the privateInfo from all users in a relationship with the current user? I've seen the usage of innerqueries in the documentation and I think that's what I should be using, but the usage of ParseObjects is making this confusing to me, since i'd have to work with PrivateInfo and Relationship ParseObjects, and not a User parseObject, which is what is being pointed by the privateInfo class.
An easily missed part of the documentation is the Relations Guide that explains the different types of relationships in much more detail than I can in an answer.
In regards to doing a query for "userA", looking to get all PrivateInfo objects that are for users that have a Relationship record that points to "userA":
ParseQuery<ParseObject> relationQuery = ParseQuery.getQuery("Relationship");
relationQuery.whereEqualTo("user", userA);
ParseQuery<ParseObject> privateInfoQuery = ParseQuery.getQuery("PrivateInfo");
// find records where PrivateInfo.user == Relationship.relatedToUser
privateInfoQuery.whereMatchesKeyInQuery("user", "relatedToUser", relationQuery);
// if you also need the User so you can show info about them
privateInfoQuery.include("user");
This assumes your classes have the following columns:
PrivateInfo
user : Pointer<_User>
Relationship
user : Pointer<_User>
relatedToUser : Pointer<_User>
If you need to get Private info for reverse relationships too, it gets trickier. I can provide a sample OR query if needed.
You might want to look over the REST Api docs on ACL and on security..
Wnen you have User A in relation w/ B, you can UPD ACL READ on B's privateInfo , giving A read access.
Then you can just do an 'include=ClassPointedTO' on any query and the extra class ( private info will be inlined in response to flat query with the sensitive data ).
If u drop the relation you must keep info consistent by ALSO updating the ACL element to drop read on the dropped target of the dropped relation.
--EDIT--
So when the Privateinfo entry is created, you can grant ACL READ to the creating user if you want. Or you can grant ACL READ to a Role entry that the creating user is in. Or you can do both. You would also need ACL WRITE by the creating user.
After that, in any query by any user you would get the following on a direct Query on Privateinfo or on a query utilizing "?include=Privateinfo" ...
Users with READ ( either direct or via a Role which the user belongs to ) will have in the response those Privateinfo entries where they have READ.
In my app, each user has a table of records says:
id, friend_name, message
My goal is to store this data in Android phone, so that each time a user log in, he/she can populate this list quickly. At server side, I already had a record of friend relationship...etc. Now I just want to keep a small database in Android side for each user because loading from the server takes times, plus I realize that these data are distinct among users. Let's says:
- User A has messages: a, b, c
- User B has messages: d, e, f
...
I read about SharePreference, but I guess it's inappropriate here since SP is only good for key/pair values. Then I look over sqllite database, it's straightforward. But what I don't understand is how can we make sure that each time a new user log in, he/she will have his/her own database but not others? I can keep a key/pair value flag for each user in SharedPreference to check if the database already existed, but then where do I store these databases? For n users, I would have to store n databases, that sounds impractical.
So what's the best way to store my data in this case?
You wouldn't create a new database for each user. What you need to focus on is good database design. In this particular case you would create a table for messages, a table for users and a table that holds links between users and messages using their ids. When a user logs into your app, you would find the messages that are linked to this user. A good database design also makes sure there is no redundant data (=duplicate data, for instance storing the same message twice). Look into database normalization if you want to learn more about that.
You can use UUID.getRandomUUID() behaviour. I have seen this at GOOGLE I/O Protips movie.
http://www.youtube.com/watch?feature=player_embedded&v=twmuBbC_oB8