I am struggling with Parse Relational Queries.
What I want to do: To query all Recipes that current ParseUser likes.
Models (Pseudo code to simplify)
There are two classes. One is Recipe class, another one is Like class that has information of who likes which recipe.
#ParseClassName("Like")
public class Like ParseObject{
"fromUser" : ParserUser
"toRecipe": Recipe
}
#ParseClassName("Recipe")
public class Recipe : ParseObject {
"objectId": String // from ParseObject
// some other field.
}
I have tried both whereMatchesQuery() and whereMatchesKeyInQuery() methods. But both query results are an empty list. Does someone know how to query to meet my requirement?
Case of using ParseQuery.whereMatchesQuery()
ParseQuery<Like> likesQuery = ParseQuery.getQuery(Like.class);
likesQuery.whereEqualTo("fromUser", ParseUser.getCurrentUser());
ParseQuery<Recipe> recipesQuery = ParseQuery.getQuery(Recipe.class);
recipesQuery.whereMatchesQuery("toRecipe", likesQuery);
recipesQuery.find() <- Return Empty List
Case of using ParseQuery.whereMatchesKeyInQuery()
ParseQuery<Like> likesQuery = ParseQuery.getQuery(Like.class);
likesQuery.whereEqualTo("fromUser", ParseUser.getCurrentUser());
ParseQuery<Recipe> recipesQuery = ParseQuery.getQuery(Recipe.class);
recipesQuery.ParseQuerywhereMatchesKeyInQuery("objectId", toRecipe", likesQuery);
recipesQuery.find() <- Return Empty List
With the current design, it seems you can only fetch likes and then get Recipes with get:
ParseQuery<Like> likesQuery = ParseQuery.getQuery(Like.class);
likesQuery.whereEqualTo("fromUser", ParseUser.getCurrentUser());
List<Like> likes = likesQuery.find();
List<Recipe> recipes = new ArrayList(likes.size());
for (Like like : likes) {
recipes.add(like.getRecipe());
}
You can use query.include() to include the recipe object in the query results.
Another option is to add a recipe id field to likes:
#ParseClassName("Like")
public class Like ParseObject {
"fromUser" : ParserUser
“toRecipe” : Recipe
"toRecipeId": String
}
If you do this, you can use your second suggestion with whereMatchesKeyInQuery.
Related
So i want to query my Firebase Database base on the value that i get from other activity.
private String tripID = "";
tripID = getActivity().getIntent().getStringExtra("tripID");
JoinRef = FirebaseDatabase.getInstance().getReference().child("Join").child(tripID);
FirebaseRecyclerOptions<Joins> options = new FirebaseRecyclerOptions.Builder<Joins>().setQuery(JoinRef,Joins.class).build();
Database Structure:
But it shows an exception
com.google.firebase.database.DatabaseException: Can't convert object
of type java.lang.String to type com.thesis.joinerapp.Model.Joins
While FirebaseUI can perform look ups of data for you, your data has to be in a very specific format for that.
If you want to show a subset of the number of trips, the index has to look like this:
"myTrips": {
"tripID1": true,
"tripID2": true
}
Where tripID1 and tripID2 are the -L keys that you have under /Trip.
You can find another example of this data in the FirebaseUI documentation on showing indexed data.
when you want to use the FirebaseUi, your database structure should be like this.
{
"Join" : {
"tripID" : {
"pushUid" : {
"joinID" : "yourJoinID",
"personCount" : "1",
"tripID" : "yourTrioID",
"uid" : "yourUid"
}
}
}
}
You need to add new root child which is pushId.
I have a list of Teachers that each contain a list of Student objects. Each Student contains a list of schoolbooks that he has to bring each day. It looks like this:
Teacher {
String teacherName;
RealmList<Student> students = new RealmList<>();
}
Student {
String studentName;
RealmList<SchoolDay> schooldays = new RealmList<>();
}
SchoolDay {
String day;
RealmList<RealmString> schoolbooks;
}
(RealmString is simply primitive String wrapped as a RealmObject)
I want to extract the list of schoolbooks for a certain student on a certain day - several students might have the same schoolbooks, but I'm only interested in the books for one particular student on one particular day (for example, Sunday). A student might be in the classes of several teachers, but I'm only interested in the result for one of them as the weekly booklist will be different for each one. Sample query data might be:
teacher : steven
student : austin
day : sunday
This is where I get stuck - how do I subquery this? To get the teacher that I'm interested in:
RealmResults<Teacher> = realm.where(Teacher.class).equalTo("teacherName", "steven").findAll();
However, I then have to run a subquery on the teacher and a subquery on the student - or better yet, run all of them in the same query somehow. What I want to get as my final result is just the string representing the schoolbooks for that one particular student. How can I do this?
I would propose an easier option.
You can make use of inverse relationships:
The models will look like:
Teacher {
String teacherName;
RealmList<Student> students = new RealmList<>();
}
Student {
String studentName;
RealmList<SchoolDay> schooldays = new RealmList<>();
#LinkingObjects("students")
final RealmResults<Teacher> teacher = null;
}
SchoolDay {
String day;
RealmList<SchoolBook> schoolbooks;
#LinkingObjects("schooldays")
final RealmResults<Student> student = null;
}
SchoolBook {
String bookName;
#LinkingObjects("schoolbooks")
final RealmResults<SchoolDay> day = null;
}
And the query will be as simple as:
RealmResults<SchoolBook> = realm
.where(SchoolBook.class)
.equalTo("day.student.studentName", "austin")
.findAll();
Can you try like that :
realm.where(Teacher.class)
.equalTo("teacherName",teachername)
.equalTo("students.studentName",studentname)
.equalTo("students.schooldays.day",day).findAll();
After all you have Teacher object(s) and you can get variables in one query :
RealmResults<Teacher> teachers= your query above;
for(Teacher teacher:teachers){
//remember still you can have multiple students for given teacher
for(Student student:teacher.getStudents()){
for(Schoolday schoolday:student.getSchooldays()){
schoolday.schoolbooks bla bla bla...
}
}
}
Why we using for loop : because findAll() method can return multiple results, if you want single Teacher object use findFirst()
This will return you Teachers of given teachername attribute that contains/includes students with given student name : studentname and those students have schooldays with given: day name.
I think the last explaination is quite a bit hard to understand, now I explain it with examples:
In first query you are getting Teachers with name= "Yasin".
Assume that after this query you got 5 Teachers with name "Yasin".
Then in second query you are searching this 5 Yasin teachers; if their one of students name is "Jon". Assume that you have 3 Yasin teachers after that query.
Then in the last query you searching of that 3 "Yasin" teachers; if their one of students school day is "Sunday".
You can take a look at this question : how-to-make-a-nested-query-in-realm
Also this question is good for referencing ; it was helpful for me: realm-android-nested-query
I have three parse subclasses: Recipe, Ingredient, and RecipeIngredient. RecipeIngredient has a pointer to a Recipe, and a pointer to an Ingredient.
When I am trying to create a QueryFactory to get all the ingredients for a recipe. I am trying to do this with whereMatchesKeyInQuery, but the objectIds aren't matching. From the docs, it appears that this should be legal. What am I missing?
public MeatIngredientListAdapter(Context context, final String recipeName) {
super(context, new ParseQueryAdapter.QueryFactory<Ingredient>() {
public ParseQuery<Ingredient> create() {
ParseQuery<Ingredient> query = ParseQuery.getQuery(Ingredient.class);
query.whereEqualTo("isMeatOrFat", true);
ParseQuery<RecipeIngredient> riQuery = ParseQuery.getQuery(RecipeIngredient.class);
riQuery.whereEqualTo("recipeName", recipeName);
riQuery.include("ingredient");
riQuery.whereEqualTo("isMeatOrFat", true);
query.whereMatchesKeyInQuery("objectId", "ingredient.objectId", riQuery);
return query;
}
});
}
In your case the use of whereMatchesKeyInQuery is overkill. I might not have enough information to make this call about your app but is seems that you would be able to cut out the need for RecipeIngredient all together if you just create a Relation of the Ingredient class inside the Recipe class. This will simplify your queries and make your app more scalable and give you features (explained below). If you had a data structure like this:
Recipe Class
- Name (String)
- ingredients (Relation of the Ingredient class)
Ingredient Class
- <Columns to describe the ingredient that you already have in place>
Now you can store one recipe that "points" (using relations) to many ingredients.
So an example entry might look like this:
Recipe
Name
PB&J
ingredients
Peanut Butter //this is a relation to the Peanut Butter Ingredient object
Jelly //this is a relation to the Jelly Ingredient object
Ingredient
Name
Peanut Butter
Calories
...
Cost
...
And here in code we add the data to the classes:
ParseObject ingredient1 = new ParseObject(Ingredient.class);
ingredient1.put("Name", "Peanut Butter");
ParseObject ingredient2 = new ParseObject(Ingredient.class);
ingredient1.put("Name", "Jelly");
ParseObject recipe = new ParseObject("Recipe");
recipe.put("Name", "PB&J");
ParseRelation<ParseObject> relation = recipe.getRelation("ingredients");
relation.add(ingredient1);
relation.add(ingredient2);
recipe.saveInBackground();
The magic behind this setup is that we can now specify a recipe by name and get all ingredients like you wanted but we can also retrieve all recipes that have certain ingredient(s) in them (this is the beauty of a many-to-many relationship) and on top of that it simplifies your queries.
Now for the original query you wanted with this new setup:
ParseObject recipe = ...; // "PB&J" Recipe object.
ParseRelation relation = recipe.getRelation("ingredients");
// generate a query based on that relation
ParseQuery query = relation.getQuery();
query will hold all of the ingredients for the recipe object when the query is executed.
Now suppose you want to create a query where you get all of the recipes that contain a certain ingredient:
ParseObject ingredient = ...
ParseQuery<ParseObject> query = ParseQuery.getQuery("Recipe");
query.whereEqualTo("ingredients", ingredient); //use whereContainedIn for multiple ingredients
query will contain all Recipe objects that have the specified ingredient in their ingredients relation column when the query is executed.
I hope this helped you. Please let me know if I severely misunderstood the structure of your app - if so I will revise my answer if you give me new information but honestly I think the "middle man" RecipeIngredient is forcing you to complicate your app.
i have basic question. Iam using parse android SDK to retrieve some data from backend. I have 2 collections : "User" and "Photo". What i want to do is that i want to query "Photo" collection which contains some data about image and join that against "User" collection and get some info about owner of picture. Please see code below:
ParseQuery<ParseUser> queryInner = ParseUser.getQuery();
ParseQuery<ParseObject> query = ParseQuery.getQuery("Photo");
query.whereMatchesKeyInQuery("owner", "username", queryInner);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> resultSet, ParseException exception) {
if (exception == null) {
parsqQueryResult = new ArrayList<ObjectUserPhoto>();
ObjectUserPhoto row = new ObjectUserPhoto();
Log.e("size",String.valueOf(resultSet.size()));
for (int a = 0; a < resultSet.size(); a++) {
row = new ObjectUserPhoto();
//this works
row.setDescription(resultSet.get(a).getString(Constants.DB_COL_USER_PHOTOS_DESCRIPTION));
//this is not working
Log.e("username",String.valueOf(resultSet.get(a).getString("col_from_user_table")));
parsqQueryResult.add(row);
}
}
}
});
So basically iam able to acces columns from "Photo" collection, but iam not able to acces any column from "User" collection. How can i acces data from "User" collection ??
Thanks
Martin
In your comment you mentioned that you are not using pointers. I assume that you are just storing the id of the ParseUser objects.
Given a ParseObject's ID, you can retrieve an object by issuing a ParseQuery and passing the ID. Refer to this document.
However, I do not see any reason why you would want to store just the ID and not the Pointer to the object. Imagine if you want to display the information on a list then that means for every item you will need to perform a ParseQuery.
If you store a Pointer then you can leverage on the "include" method (see it here at the bottom part of the "Relational Queries"). This allows you to include the actual object the Pointer is pointing to. So in your case, the results of the Photo query will include the User objects too.
And lastly, I suggest that you read through at least the whole Objects and Queries sections of the documentation as you would learn the basics on how to use the SDK.
I'm writing a Xamarin Android app which is using Parse.com as the backend. I'm running a query against a Parse Class called Beacons, of which one of the columns is a Pointer to another class called BeaconCat.
I'm therefore using two queries as shown below, but when it returns the data, it lists ALL of the categories within the BeaconCat class, not just the one which matches the initial query.
I'm expecting just one category, not all 13 of them. Any idea why?
// First query on class 1.
var innerQuery = ParseObject.GetQuery("Beacons");
innerQuery.WhereEqualTo("minor", minor);
// Query on class 2 which passes in first query.
var newQuery = ParseObject.GetQuery("BeaconCat");
newQuery.WhereMatchesQuery("Category", innerQuery);
IEnumerable<ParseObject> Myresults = await newQuery.FindAsync();
foreach (var result in Myresults)
{
var category = result.Get<string>("Category");
Console.WriteLine ("Category " + category);
}