I'm making a small application. trying to retrieve posts inserted, and then I want to retrieve only new inserted posts, and not retrieving all the posts again.
So do you have any idea on how to I can retrieve last items ( Since the list object retrieved)
Here my Query code :
public void getFeed(int limit, int skip){
ParseQuery<ParseObject> query = ParseQuery.getQuery("Feed");
query.setSkip(skip);
query.setLimit(limit);
query.setCachePolicy(ParseQuery.CachePolicy.CACHE_ELSE_NETWORK);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> feedList, ParseException e) {
if (e == null) {
for (int i = 0; i < feedList.size(); i++) {
Post p = new Post(feedList.get(i).get("Text").toString());
mAdapter.addItem(p);
}
Log.d("result", "Here is it:" + feedList.size());
mRecyclerView.setAdapter(mAdapter);
} else {
Log.d("Feed", "Error: " + e.getMessage());
}
}
});
}
keep the last time you checked and then use that time to pull anything greater than the last time checked from the createdAt column or updatedAt column (if its possible for someone to update something you are pulling) of the object. then after your query is finished update that time to the current time.
you can store the viewed posts count and next time when retrieving the list set the count as parameter for skip:
query.setSkip(count);
Related
I feel like I'm pretty close on this one, just need the last bit.
I have the following tables:
_User (standard Parse table)
Category (object Id, name)
Exercises (object Id, name, description, thumbnail, image, etc)
and UserFavourites which is where I store the user's preferred exercises
(objectId, user->users table, exercise->exercises table, category->category table)
I have writing to Parse using pointers just fine:
//create new parse object
ParseObject favouriteExercise = new ParseObject("UserFavourites");
//create pointers to the Exercise table and Category table
ParseObject exercise = ParseObject.createWithoutData("Exercises", mExerciseId);
ParseObject category = ParseObject.createWithoutData("Category", mCategoryId);
//put those pointers into the Userfavourites table and save
favouriteExercise.put("user",ParseUser.getCurrentUser());
favouriteExercise.put("exercise",exercise);
favouriteExercise.put("category",category);
//save
favouriteExercise.saveInBackground();
Now I'm trying to retrieve all the exercises a user has favourited and put them in to a listview by searching the table for any objects that match the user's pointer to the user's table:
ParseQuery<Exercises> query = ParseQuery.getQuery("UserFavourites");
final ParseObject user = ParseObject.createWithoutData(ParseUser.class, ParseUser.getCurrentUser().getObjectId());
query.whereEqualTo("user", user);
//call to parse.com to start the query
query.findInBackground(new FindCallback<Exercises>() {
#Override
public void done(List<Exercises> exercises, ParseException e) {
if (exercises != null) {
Toast.makeText(getApplicationContext(), "Favourites found, can't list yet", Toast.LENGTH_SHORT).show();
mAdapter.clear();
//add all the exercises to the list
mAdapter.addAll(exercises);
//sort the list alphabetically
mAdapter.sort(new Comparator<Exercises>() {
#Override
public int compare(Exercises exercises, Exercises t1) {
return exercises.getName().compareTo(t1.getName());
}
});
} else {
mNoFavourites.setVisibility(View.VISIBLE);
}
Where I'm stuck is when I run this I can see my query is working -> I am retrieving the 4 rows in UserFavourites that I favourited out of the table of 8, so it is filtering correctly, but the objects I'm getting aren't pointing to the exercises I want. They are just empty pointers.
Thanks.
Yes it will return only reference (Pointer). If you want actual object data call fetchInBackground
myObject.fetchInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (e == null) {
// Success!
} else {
// Failure!
}
}
});
I figured it out based on the logic kishore jethava gave.
I queried the favorites table, then with the results I wanted (which pointed to another table) I cycled through each result and got the object it pointed to and added it to my ArrayList.
public void getFavourites() {
//set progress bar
setProgressBarIndeterminateVisibility(true);
ParseQuery<Exercises> query = ParseQuery.getQuery("UserFavourites");
final ParseObject user = ParseObject.createWithoutData(ParseUser.class, ParseUser.getCurrentUser().getObjectId());
query.whereEqualTo("user", user);
query.include("exercise");
//call to parse.com to start the query
query.findInBackground(new FindCallback<Exercises>() {
#Override
public void done(List<Exercises> objects, ParseException e) {
if (objects.size() != 0) {
for(ParseObject object : objects)
{
//for each pointer found, retrieve the object it points to
obj = object.getParseObject("exercise");
mAdapter.add((Exercises) obj);
}
});
}
} else {
mNoFavourites.setVisibility(View.VISIBLE);
}
//stop progress bar
setProgressBarIndeterminateVisibility(false);
}
});
}
I wasn't sure how to frame the question title, but, here is what i am trying to do.
Using Parse.com
I have a table - Surveys and it has a column with Array datatype. I have a JSONArray stored in this column. The JSONArray has 3 JSONObjects. I have to loop through the 3 JSONObjects, get a field with key "type" and use the value (for example "type_dob") of this key, to query a separate table again. I need this to be done in a row, for example once the result for first key is retrieved, then i have to perform the query for second key.
How can i achieve this?
Sample JSON: Questions: [{"type":"type_dob","id":"I27y16N5gX"},{"type":"type_text","id":"jGAujtNNZc"},{"type":"type_radio","id":"cCDlrrJYKI"}]
My present code:
public void getDataFromServer() {
ParseUser user = ParseUser.getCurrentUser();
if (user != null) {
showProgressDialog("Getting Survey details...");
int survey_count = user.getInt(Const.Parse_User.SURVEY_COUNT);
Log.d(Const.DEBUG, "Survey Count: " + survey_count);
String current_survey = "survey_" + (survey_count + 1);
Log.d(Const.DEBUG, "Current Survey: " + current_survey);
ParseQuery<ParseObject> query = ParseQuery.getQuery("Surveys");
query.whereEqualTo(Const.Parse_SURVEYS.SURVEY_ID, current_survey);
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list, ParseException e) {
dismissProgressDialog();
if (e != null) {
Log.d(Const.DEBUG, "Exception while getting data from Parse - Surveys table");
} else {
if (list.size() > 0) {
ParseObject object = list.get(0);
try {
String questions_array = object.getJSONArray(Const.Parse_SURVEYS.QUESTIONS).toString();
Log.d(Const.DEBUG, "Questions: " + questions_array);
JSONArray array = object.getJSONArray(Const.Parse_SURVEYS.QUESTIONS);
for (int i = 0; i < array.length(); i++) {
JSONObject jsonObject = array.getJSONObject(i);
String type = jsonObject.get("type").toString();
//I should write the query for getting data from table matching the String type. //If i do a findInBackground query for each of the key, then its done in a background thread
//and the for loop exists even before the result for first key comes back.
//How can i handle this?
}
} catch (Exception e1) {
e1.printStackTrace();
}
}
}
}
});
}
}
Let me know if you need anything else?
I think you are moving slightly in a unfortunate direction with your db design.
As far as I can tell from you question, the better approach for you would be to store an Array of pointers. For instance, having a data class in Parse.com called 'Question', which stores a type and whatever other properties you need.
Now assume you have an Array instead in your 'Surveys' class. Then your code gets rather simple:
ParseQuery<ParseObject> query = ParseQuery.getQuery("Surveys");
query.whereEqualTo(Const.Parse_SURVEYS.SURVEY_ID, current_survey);
query.include(Const.Parse_SURVEYS.QUESTIONS); // <- IMPORTANT
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list, ParseException e) {
ParseObject object = list.get(0);
// get all Question objects
List<ParseObject> array = object.getList(Const.Parse_SURVEYS.QUESTIONS);
// no need to fetch, the data is here
for (ParseObject question: array) {
String type = question.getString("type");
String question = question.getString("question");
List<String> answerOptions = question.getList("options")
...
}
}
}
If for some reason you cannot transition to this design, then I believe you want to look into Bolts https://github.com/BoltsFramework/Bolts-Android. With this you get the same async abilities as Promises does in javascript. This means that you can que up a range of background jobs and return only when all are completed.
Though Bolts will aid you, it will not avoid exiting your for-loop before it has completed. This is however just a matter of design, meaning that as long as you are aware of the flow of our program, you can design it accordingly. For instance delaying the dismiss of a progress dialog until all background tasks has completed (or failed).
I however suggest that you look into the documentation about the query.include() capabilities together with pointer arrays.
i fetched data like this way from data parse table.
ParseQuery<ParseObject> query = ParseQuery.getQuery("Surveys");
query.whereEqualTo(Const.Parse_SURVEYS.SURVEY_ID, current_survey);
query.include(Const.Parse_SURVEYS.QUESTIONS); // <- IMPORTANT
query.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> list, ParseException e) {
ParseObject object = list.get(0);
// first initilization Jsonobject Array list.
List<JSONObject> jsobj = new ArrayList<JSONObject>();
jsobj = object.getList(Const.Parse_SURVEYS.QUESTIONS);
// no need to fetch, the data is here
for (int i = 0; i < jsobj.size(); i++) {
Log.e("in the For loop ", ": : ::111111 : " + jsobj.get(i));
JSONObject arr1 = new JSONObject((Map) jsobj.get(i)); // jsobj.get(i);
Log.e("in the For loop ", ": : ::111111 : " + arr1);
try {
Log.e("in the For loop ",
": : ::111111 : " + arr1.getString("name"));
// hear u want to store data in Custom Array list.
// other wise u store in single String value
String type = arr1.getString("type");
String question = arr1.getString("question");
String options = arr1.getString("options");
// this is my custom getter setter class
GetIngredients ai = new GetIngredients();
ai.setName(arr1.getString("type"));
ai.setQty(arr1.getString("question"));
ai.setUnit(arr1.getString("options")) ;
// this is my custom array
arr_Ingredients.add(ai);
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Log.e("in the For loop ", ": : :: : " + jsobj.get(i));
}
}
in my parse data base column type is "Array".
I am having some trouble getting some data from my Parse table/object with a query. I am trying to simply make a query which looks for the current Parse User's objectID in the "sender" column. When that result is returned, I want to extract the receiver's objectID from the "receiver" column associated with the user that I searched for. I keep getting 0 results, even though I know the data is there. Here is my code:
private List<String> potentialRelationQuery() {
mPotentialRelations = new ArrayList<>();
String currentUserId = mCurrentUser.getObjectId();
ParseQuery<ParseObject> query3 = ParseQuery.getQuery("PotentialRelation");
query3.whereEqualTo("sender", currentUserId);
query3.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> parseObjects, ParseException e) {
if (e == null) {
if (parseObjects.size() > 0) {
for (int i = 0; i < parseObjects.size(); i++) {
ParseUser receiver = (ParseUser) parseObjects.get(i).get("receiver");
String receiverId = receiver.getObjectId();
mPotentialRelations.add(receiverId);
}
}
} else {
Log.d("MyApp", "No matching objects returned from request");
}
}
});
return mPotentialRelations;
}
Since findInBackground is an asynchronous call to Parse isn't it possible that mPotentialRelations returns empty because the findInBackground query hasn't yet completed before the potentialRelationQuery method returns? I know I've had issues with this. Since you can't return data from an inner class (i.e. in the done method of FindCallback), writing this kind of query method has never really worked consistently for me.
I've built an application that uses Parse. My application allows users to register, login and then post to a parse cloud database.
I have two Parse classes, one called User and one called Posts. User is made up of ObjectId, username and password, and Posts is made up of ObjectId, text and user. Of which user is a pointer to ObjectId within the User class.
I've created a method in my app called getData() which contains a ParseQuery, this queries the Posts class, selects the text field and includes the user field. The query then retrieves the data into a List and then loops through each row of the List, collecting the String from the text field and then adds it into a ListView on the UI using postList.add(textList.get(i).getString("text")); each time the program goes through the loop.Within the loop is another query, which queries the User class, selects the objectId field, I then add a constraint to the query to tell it to only retrieve data where the objectId field is equal to the user field within the Posts class(I think).
ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
queryUser.selectKeys(Arrays.asList("objectId"));
queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
Next I want to take the collected username data that the query retrieved, put it into a String and display it on screen in a toast. So basically the getData() method should collect all of the strings from the text field and the username of the user that posted it. The problem is that I'm unsure if i'm trying to go about this in the right way. My app throws an error when this piece of code is executed so I'm obviously doing something wrong.
java.lang.IllegalStateException: ParseObject has no data for this key. Call fetchIfNeeded() to get the data.
at com.parse.ParseObject.checkGetAccess(ParseObject.java:3235)
at com.parse.ParseObject.getString(ParseObject.java:2817)
at com.text.parse.MainActivity$3.done(MainActivity.java:186)
Code at line 186 : queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
My questions are:
1. Am I trying to do this in the right way?
2. Why am I receiving this error?
Code for getData() method:
public void getData() {
final ArrayList<String> postList = new ArrayList<String>();
final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.listview_row, postList);
final ParseQuery<ParseObject> queryPosts = ParseQuery.getQuery("Posts");
queryPosts.selectKeys(Arrays.asList("text"));
queryPosts.include("user");
queryPosts.addDescendingOrder("createdAt");
queryPosts.setLimit(20);
queryPosts.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> textList, ParseException e) {
if (e == null) {
//query successful
for (int i = 0; i < textList.size(); i++) {
postList.add(textList.get(i).getString("text"));
ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
queryUser.selectKeys(Arrays.asList("objectId"));
queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
queryUser.setLimit(20);
queryUser.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> userList, ParseException e) {
if (e == null) {
String s = userList.get(0).getString("username").toString();
Toast.makeText(MainActivity.this, s, Toast.LENGTH_LONG).show();
}
else {
//query error
Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
}
}
});
}
lvText.setAdapter(listAdapter);
} else {
//query error
Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
}
}
});
}
Sorry for the long question. Any help would be greatly appreciated, thanks.
UPDATE:For anyone stuck with a similar problem, here's how I got it to work:
public void getData() {
final ArrayList<String> postList = new ArrayList<String>();
final ArrayAdapter<String> listAdapter = new ArrayAdapter<String>(this, R.layout.listview_row, postList);
final ParseQuery<ParseObject> queryPosts = ParseQuery.getQuery("Posts");
queryPosts.include("user");
queryPosts.addDescendingOrder("createdAt");
queryPosts.setLimit(20);
queryPosts.findInBackground(new FindCallback<ParseObject>() {
#Override
public void done(List<ParseObject> textList, ParseException e) {
if (e == null) {
//query successful
for (int i = 0; i < textList.size(); i++) {
postList.add(textList.get(i).getString("text"));
ParseObject po1 = textList.get(i);
ParseObject po2 = po1.getParseObject("user");
String username = po2.getString("username");
Toast.makeText(MainActivity.this, username, Toast.LENGTH_SHORT).show();
}
lvText.setAdapter(listAdapter);
} else {
//query error
Toast.makeText(MainActivity.this, "query error: " + e, Toast.LENGTH_LONG).show();
}
}
});
}
You simply include the column in the class you are querying that holds a pointer to another class, that then gives you access to all of the columns of data within the second class.
This method as shown is doing nothing useful:
ParseQuery<ParseObject> queryUser = ParseQuery.getQuery("User");
queryUser.selectKeys(Arrays.asList("objectId"));
queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
The selectKeys statement is telling it to only return the contents of the objectId column, which you are passing in to the whereEqualTo statement as a parameter... seems silly to run a query to get a value you already have!?. I would not user selectKeys until you think you need to optimise your queries. The only use this query would have is to let you know if the objectId is valid, since the query will return null if it isn't a valid objectId for a User.
I'm hoping that you want to get more information about the user, so if you remove selectKeys then the other columns will be returned.
The fact that fetchIfNeeded is throwing an exception on due to this line:
queryUser.whereEqualTo("objectId", textList.get(i).getString("user"));
That suggests that textList.get(i).getString("user") is not returning an objectId for a user. If that is instead returning a username as suggested by some of your other comments (not sure here), then you need to change that line of code to read:
queryUser.whereEqualTo("username", textList.get(i).getString("user"));
If there are some other questions you have, you'll need to be a bit more precise in your questions as it isn't really clear what you're asking at the moment.
I have created 5 tables in parse.com for my Android App:
1. users (name, password,phone, etc)
2. list (List-name ,Note, Image,user)
3. subscribe_user_list (list, user)
4. favorite_user_list (list, user)
5. contacts (contact_name, number, list)
Every list has multiple contacts. A user can subscribe to a list and can mark a list as favorite.
I want to get all lists from list table to which user has subscribed with following details for every list:
1. Total count of users who have subscribed to the list
2. Total number of users who have marked the list as favorite
3. Total number of contact in that list.
This is easily possible in SQL using multiple join queries, however, I don't know how to get this in a single query in parse. Is there anyone who can help me in this..
You can use compound queries to create queries based on other queries results.
"you must create a separate table in which the relationship is tracked.
This table, which we will call Favourite, would have a 'User_Id'
column and a 'Favourite_Id' column, each with a pointer to a Parse User."
currentUser = ParseUser.getCurrentUser();
ParseQuery<ParseObject> query = ParseQuery.getQuery("Favourite");
query.whereEqualTo("User_Id", currentUser);
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> objectList, ParseException e) {
if (e == null) {
userList = new ArrayList<ParseObject>();
parseUsers = new ArrayList<ParseUser>();
for (int i = 0; i < objectList.size(); i++) {
userList.add((ParseObject) objectList.get(i).get("Favourite_Id"));
}
for (int i = 0; i < userList.size(); i++) {
userList.get(i).fetchIfNeededInBackground(new GetCallback<ParseUser>() {
#Override
public void done(ParseUser object, ParseException e) {
if (e == null) {
parseUsers.add(object);
}
}
});
}
}
}
});