One to many relation on Parse.com - android

I have two classes on Parse.com : Image & User. In User class, I am saving 3 fields Name,Mobile-number & Occupation. In Image class I'm saving images.
I have to create one-to-many relation between these two classes so that I can fetch images with the corresponding mobile-number.
I have created a relation between User class and Image class on parse.com with a column named Mobile in User class. Not able to find how can I fetch the images with that particular mobile number with one-to-many relation. Please help as I have gone thru the documentation. Thanks in advance.

This is just the code to go about. You will have to think about organizing your classes thoughtfully. I am not sure how you intend to go but as far as coding is involved, the following should help.
First get the current user.
ParseUser currentUser = ParseUser.getCurrentUser();
Since, you have "mobile" column as the relation in the User table, get the relation first.
Like this.
ParseRelation<ParseObject> relation = currentUser
.getRelation("mobile");
Once you get the relation, get the query on the object who require. In your case, it is the Image Object.
ParseQuery<ParseObject> query = relation.getQuery("Image");
From here, you can customize your query. Eg:
query.getFirstInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject, ParseException e) {
if(e == null)
//your code
//List<ParseFile> pFileList = (ArrayList<ParseFile>) object.get("images"); //something like this just to give an idea
}
});
Or if you have multiple objects, use
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> list, ParseException e) {
if (e == null) {
for (ParseObject object : list) {
ParseFile image = (ParseFile) object.get("images_column_name");
}
}
}
});

If an Image class only has one User it is related to, simply use a reference property. You could call it owner or user or whatever. You then just set this to the current user (or any other user).
Internally Parse will store just the ID of this object with some extra information to make this as a link to another class.
When you query you can simply use the current user (or any other user) to compare against that property. Again, Parse will internally just compare ID's, you don't have to think about it.
Look at the documentation here. See where it sets the parent property of the Comment to an instance of the Post? That's the sort of thing you want to do.
Using the mobile number to link is a bad idea, as if you change the number on a User then all the Image classes using that number are now orphaned, unless you write extra code to handle this.

Related

Search child nodes in firebase database using android

Hello guys here is my firebase database:
I want to get list of all medicines with particular symptoms.
Here is my code i.e what i have done
public void initializeMedicineListener(String node,String type,String value){
mDatabase=mFirebaseInstance.getReference();
Query query = mDatabase.child("Medicine").child("symptoms").orderByChild("name").equalTo("Neck pain");
query.addListenerForSingleValueEvent(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
medicineList=new ArrayList<Medicine>();
if (dataSnapshot.exists()) {
for (DataSnapshot medicine : dataSnapshot.getChildren()) {
Medicine data = medicine.getValue(Medicine.class);
medicineList .add(data);
}
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
}
});
}
But i am getting null results.
Please guide me guys.Am i doing something wrong??
When you run a query at a location, Firebase check each child node at that location for the property that you order on and the range/condition you filter on.
mDatabase.child("Medicine").child("symptoms").orderByChild("name").equalTo("Neck pain");
So this checks the children of /Medicine/symptoms for their name property and only returns them if they have a value equal to Neck pain.
There are two problems with this:
Your JSON doesn't have a /Medicine/symptoms. Instead you have a Medicine, where each child node has a symptoms node.
Even if it did, your symptoms child doesn't have a value Neck pain. Instead you have an array, where each value may be Neck pain.
The closest you can now get to the query you want is:
mDatabase.child("Medicine").orderByChild("symptoms/0/name").equalTo("Neck pain");
This query returns medicines for which the first symptom name is equal to Neck pain. Firebase cannot perform a query across all array members to see if it contains a specific value in any position.
As usual with NoSQL databases: if you can't perform the use-case you want with your current data structure, you can typically change/expand your data structure to allow the use-case. And usually this is done by very directly mapping what you want to show on your screen to the structure in the database.
Your current data structures allows you to efficiently look up the symptoms (and other data) for a given medicine. That's great. It does however not allow you to efficiently look up the medicines for a given symptom. To allow that you can for example add a structure that maps each specific symptom back to its medicines:
symptoms
"Neck pain"
-L6hb2...bRb0: true
-L6rW...Fuxkf: true
With this additional structure (known as an inverted index or reverse index) you can now look up the medicines for Neck pain by simple loading /symptoms/Neck pain.
For more on this approach to categorization, see my answer here: Firebase query if child of child contains a value
You can't work with firebase database as relational databases .. instead of what you looking for .. you can create new node like this
medicineSymp
---neckpain
-------medicine1ID
-------medicine1ID
-------medicine1ID
this way you could get all medicines much faster and easier

Lazy loading on firebase?

I am trying out firebase database and I was checking the recommended way of modeling many to many or one to many relationships.
Say I have this relationship between post and user:
user has many posts.
This is my approach for the model design:
class User{
List<String> postIds;
...
}
class Post{
String userId;
....
}
This is according to the firebase documentation here.
I like the design instead of embedding posts created by a user under user collection like the mongodb style this design is flat; so later time if we want to fetch only users on the system we dont have to pull the posts under the users as well.
But my doubt with this design is even embedding the ids within the posts could be a problem later on; imagine I have 100 users with 1000 posts each. If I want to show list of users I have to pull 100 users which means I have to pull 100,000 post ids.
Is there any lazy loading concept on firebase? ie when I fetch a user entity the postIds should not be loaded automatically; it should be loaded on demand.
There is no "lazy loading" or "load on demand" construct present in Firebase at the moment. All the data under a location is read and transferred on access. One thing you can do is separate out the User and UserInfo to two different branches so you can access users separately without pulling in the excessive data.
class User {
String id;
String name;
String gender etc.
}
class UserInfo {
List<String> postIds;
Other info maintained per user
}
In this way, you can read the users without pulling extra information.
An important rule in Firebase is to have the data as flatten as possible. You can take a look at this post, Structuring your Firebase Data correctly for a Complex App, for a better understanding.
Because there is no way in the Firebase Database to download just one property of each node, the single way to achieve this is to use a new node that hosts all those ids. So if you want an efficient way to verify the existens of an id or to count all the users, download just the list of ids. For good measure you should keep precisely that list of ids in the database.
To get all those ids, you can use this code:
DatabaseReference postRef = FirebaseDatabase.getInstance().getReference().child("Post");
postRef.addValueEventListener(new ValueEventListener() {
#Override
public void onDataChange(DataSnapshot dataSnapshot) {
for (DataSnapshot ds : dataSnapshot.getChildren()) {
String uId = ds.getKey();
Log.d("TAG", uId);
}
}
#Override
public void onCancelled(DatabaseError databaseError) {
throw databaseError.toException(); // don't ignore errors
}
});
Hope it helps.

Android parse.com I can't get second user from data base

I have two tables in data base. One is user ad the second is transaction that have pointer to the first user, pointer to the second user and int. When I try make and display list I have error. I want to display all rows that CurrentUser is in first column:
ParseUser cu = ParseUser.getCurrentUser();
query.whereEqualTo("first", cu);
and list it with firstUser, secondUser and int:
from Adapter:
ParseObject taskObject = mTask.get(position);
ParseUser first = taskObject.getParseUser("first");
holder.firsthp.setText(first.getUsername());
ParseUser second = taskObject.getParseUser("second");
holder.secondhp.setText(second.getUsername()); //this line make error
int ile = taskObject.getInt("ile");
holder.taskhp.setText(Integer.toString(ile));
return convertView;
This is how transakcja table looks: http://i.stack.imgur.com/yh83p.png
When I saving transaction (when transaction table is clear, don't have any records) and immediately read it works but when I logout and login it crashes.
And here is entire code for toDoActivity Task Adapter and hplayout:
I had problems with pasting code here so I pasted it on pastebin
http://pastebin.com/2wtQLJXE
I think I know the problem. When you are calling your query on the transaction table, the two User's are Pointers to ParseObjects, or ParseUsers in this case. You need to ensure that these objects are FETCHED as well by the ParseQuery in order to properly access their data. They are ParseObjects with data from another table, Parse does not automatically retrieve them so you must tell Parse to do so when you need that data.
Looking at ParseQuery documentation for Android we find the include method.
public ParseQuery include(String key)
Include nested ParseObjects for the provided key.
You can use dot notation to specify which fields in the included object that are also fetched.
You want to use this to include columns names to Pointers of ParseObjects so the query fetches them at the same time as fetching the rest of the data from the table, in this case your transaction table.
Add this:
ParseQuery<ParseObject> query = ParseQuery.getQuery("transakcja");
query.whereEqualTo("first", cu);
query.addDescendingOrder("createdAt");
query.include("first");
query.include("second");
The reason first is having no null issues, is it is the Pointer to the current ParseUser logged in, which doesn't need to be fetched as it's data is accessible. The second one is not fetched, therefore adding the include to the query SHOULD fix this :). Make sure to also include the column "first" because I'm sure your future ParseQuery's will not always be between the current user and non-current second user

Is Parse relations/ pointers bi-directional?

This code sets up a Customer class, creates an object in it and assigns a pointer connecting the customer object to the ParseUser who created it.
ParseUser currentUser = ParseUser.getCurrentUser();
customer.put("CreatedBy", currentuser);
customer.saveInBackground;
ParseQuery<ParseObject> query = ParseQuery.getQuery("Customer");
query.whereEqualTo("CreatedBy", currentUser);
query.findInBackground(new FindCallback<ParseObject>()
The pointer is defined from Customer --> User but the query is against the customers. To go to the user I just need to check the value in the createdBy column but for the reverse an entire query is needed. Do I need to define a pointer in the other direction to optimize the query/ speed it up or does Parse enforce bidirectionality in its pointers and relations?
In a MongoDB afaik pointers must be defined in both directions for optimum query speeds. I will be using customer class much more and my app should work for 100k users+
My same doubt applies to the case of ParseRelations. I know I can use the 'include' key but is query both ways equally optimized?

How to retrieve data from multiple Parse.com Tables/Classes

I have two tables (Classes):
StudentInformation: with columns RollNumber, address, name, school
StudentMarks : with columns RollNumber, Marks1, Marks2, Marks3
I've been able to save the data from a single form into these two simultaneously, but not getting a clue on how to put a query while retrieving into a listview or any other view something like
'return rows (from both tables together) where roll number = 1234' / 'return rows (from both tables together) where Marks2 > 50'
I'm using Parse.com backend for Android
Kindly help
Thanks
First, the UI aspect of showing in a ListView is provided by ParseQueryAdapter. https://parse.com/docs/android_guide#ui-queryadapter
Regarding the query, I do not think you can join tables in the way you want. Instead, you could create a pointer in StudentMarks to StudentInformation.
Then you can query something like:
ParseQuery<ParseObject> query = ParseQuery.getQuery("StudentMarks");
query.include('studentInformation'); // include the pointer to get StudentInformation
query.whereEqualTo("RollNumber", 1234);
query.whereGreaterThan("Marks2", 50);
... // perform query
In the results StudentInformation will be available like this:
List<ParseObject> objects; // the result from the query
ParseObject studentMark = objects.get(0); // example using first object
ParseObject studentInformation = studentMark.get("studentInformation");
String studentName = studentInformation.get("name");
String studentAddress = studentInformation.get("address");
... // etc
Alternatively you could also store a Relation of StudentMarks on StudentInformation, just to let you know that this is also an option, though I do not feel like it fits your current need as well as the solution presented above.

Categories

Resources