I'm trying to use the ParseQueryAdapter to give me a list of games. I have a separate table for storing game and player pointers. In the query I'm trying to list the games, and how many players there are.
SQL style it is like this: SELECT games,count(players) FROM games JOIN participants...
I understand how can I do that with two different ParseQueries, but it only expects a single ParseQuery.
public class GamesListAdapter extends ParseQueryAdapter<ParseObject> {
public GamesListAdapter(Context context) {
super(context, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("Games");
return query;
}
});
}
How can I return a compound query here with counting all players from a different table?
It seems that you already found an answer yourself, but I post my solution here so other people may find it helpful.
In my case I have a User ParseObject and A UserPhoto ParseObject. I wanted to get only the Users' profile Images and set them in a ListView, but exclude the currentUser's(mine) profileImage from the results. Here is my working code.
public class CustomAdapter extends ParseQueryAdapter<ParseObject> {
public CustomAdapter(Context context) {
super(context, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseObject myUser = null;
ParseQuery<ParseObject> myUserQuery = ParseQuery.getQuery("User");
myDogQuery.whereEqualTo("user", ParseUser.getCurrentUser());
try {
myUser = myUserQuery.getFirst();
} catch (ParseException e) {
e.printStackTrace();
}
ParseQuery<ParseObject> userPhotoQuery = ParseQuery.getQuery("UserPhoto");
dogPhotoQuery.whereEqualTo("imageName", "profileImage");
dogPhotoQuery.whereNotEqualTo("user", myUser);
dogPhotoQuery.orderByDescending("createdAt");
return userPhotoQuery;
}
});
}
I would also like to see your code, if you have some time because I would like to see the "whereKeyDoesMatch function" implementation. Thank you!!
Related
In detail problem is I am Using parse.com as backend and I am trying to get text data into my app i have created class on parse.com and in my app also.
this is my class code from app to get data from parse:
#ParseClassName("WhatsApp")
public class WhatsApp extends ParseObject {
public String gettitle(){
return getString("title");
}
public void settitle(String title){
put("title",title);
}
public String getdes(){
return getString("des");
}
public void setdes(String des){
put("des",des);
}
#Override
public String toString() {
return getString("title")+"\n"+(getString("des"));
}
}
now how i can get 1 column data from parse only title with the help of this class and create a base adapter to design row .can anyone give me example how this can done thanks.
You can restrict the fields returned by using selectKeys method in ParseQuery.
ParseQuery<ParseObject> query = ParseQuery.getQuery("WhatsApp");
query.selectKeys(Arrays.asList("title"));;
List<ParseObject> results = query.find();
The remaining fields can be fetched later by calling one of the fetchIfNeeded variants on the returned objects:
ParseObject object = results.get(0);
object.fetchIfNeededInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
// all fields of the object will now be available here.
}
});
So I'm Implementing an app using Parse.com as back end, There is basically 3 class in Parse. The first one User where I have the User's Information, and Gallery where I have images "like Instagram, and Finally Follow Class where I have the relation following and followers.
Now I have an activity where I have to display all the images for the people I'm following only. I couldn't write a correct relational queries to get the correct result.
so this is the code that display all the images in the database not only for the people I'm following.
public class FollowingImages extends ParseQueryAdapter<ParseObject> {
public FollowingImages (Context context) {
super(context, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Gallery");
query.include("createdBy");
return query;
}
});
}
// Customize the layout by overriding getItemView
#Override
public View getItemView(final ParseObject object, View v, ViewGroup parent) {
if (v == null) {
v = View.inflate(getContext(), R.layout.list_item, null);
}
super.getItemView(object, v, parent);
// retrieving the Images from Parse.com
return v;
}
I don't know where should I apply the relational query in the constructor or inside getItemView.
please any help would be highly appreciated.
You will want to apply constraints to your query.
ParseQuery<ParseObject> query = ParseQuery.getQuery("Gallery");
query.whereEqualTo("createdBy", "theUserId");
query.findInBackground(new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (object == null) {
Log.d("score", "The find request failed.");
} else {
Log.d("score", "Retrieved the object.");
}
}
});
See the official guide for more details.
You could use the matchesKeyInQuery constraint method.
You can use the matchesKeyInQuery method to get objects where a key matches the value of a key in a set of objects resulting from another query.
(after parse docs)
So in your case (I am writing it by hand) it may be something like:
ParseQuery<Follow> whoDoIFollow = ParseQuery.getQuery("Follow")
.select("From")
.whereEqualTo("To", <user>);
ParseQuery<Gallery> theirImages = ParseQuery.getQuery("Gallery")
.whereMatchesKeyInQuery("createdBy", "From", whoDoIFollow);
If I am correct that should be an optimal way from the point of data transferred as everything happens on the server side and you only get the results(images).
Just replace
public FollowingImages (Context context) {
super(context, new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery<ParseObject> whoDoIFollow = ParseQuery.getQuery("Follow")
.select("From")
.whereEqualTo("To", <user>);
ParseQuery<ParseObject> theirImages = ParseQuery.getQuery("Gallery")
.whereMatchesKeyInQuery("createdBy", "From", whoDoIFollow);
return theirImages;
}
});
}
I feel like a broken record.
After many attempts, I have failed at getting a listview through Parse data to display a specific set of information.
Here is my model...this is all data from users:
#ParseClassName("Midwifefirm")
public class Midwifefirm extends ParseObject {
public Midwifefirm() {
// A default constructor is required.
}
//practice name
public String getPracticeName() {
return getString("practicename");
}
public void setPracticeName(String practicename) {
put("practicename", practicename);
}
//education
public String getEducation() {
return getString("education");
}
public void setEducation(String education) {
put("education", education);
}
//years in practice
public String getYearsinPractice() {
return getString("yearsinpractice");
}
public void setYearsinPractice(String yearsinpractice) {
put("yearsinpractice", yearsinpractice);
}
//practice philosophy
public String getPracticePhilosophy() {
return getString("practicephilosophy");
}
public void setPracticePhilosophy(String practicephilosophy) {
put("practicephilosophy", practicephilosophy);
}
I have this adapter; I am wondering what to place in the query section, as I just want to pull the data into the ListView that is defined in the data model:
public class CustomMidwifeAdapter extends ParseQueryAdapter<Midwifefirm> {
public CustomMidwifeAdapter(Context context) {
super(context, new ParseQueryAdapter.QueryFactory<Midwifefirm>() {
public ParseQuery<Midwifefirm> create() {
// Here we can configure a ParseQuery to display
// only top-rated meals.
ParseQuery query = new ParseQuery("Midwives");
return query;
}
});
}
#Override
public View getItemView(Midwifefirm midwifefirm, View view, ViewGroup parent) {
if (view == null) {
view = View.inflate(getContext(), R.layout.activity_midwife_result_list, null);
}
//use midwifefirm as item view/list
super.getItemView(midwifefirm, view, parent);
// find in layout the practice name
TextView titleTextView = (TextView) view.findViewById(R.id.practicename);
//in the midwifefirm data model, call getPracticename
titleTextView.setText(midwifefirm.getString("practicename"));
// Add education view
TextView EducationView = (TextView) view.findViewById(R.id.education);
EducationView.setText(midwifefirm.getString("education"));
// Add yearsexperience view
TextView ExperienceView = (TextView) view.findViewById(R.id.yearsinpractice);
ExperienceView.setText(midwifefirm.getString("yearsinpractice"));
//Add practice philosophy view
TextView PracticePhilosophyView = (TextView) view.findViewById(R.id.practicephilosophy);
PracticePhilosophyView.setText(midwifefirm.getString("practicephilosophy"));
return view;
}
}
And here is the Main Activity:
public class MidwifeResultList extends ListActivity {
private ParseQueryAdapter<ParseObject> mainAdapter;
private CustomMidwifeAdapter midwifeListAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialize main ParseQueryAdapter
mainAdapter = new ParseQueryAdapter<ParseObject>(this, Midwifefirm.class);
//which keys in Midwife object
mainAdapter.setTextKey("practicename");
mainAdapter.setTextKey("education");
mainAdapter.setTextKey("yearsinpractice");
mainAdapter.setTextKey("practicephilosophy");
// Initialize the subclass of ParseQueryAdapter
midwifeListAdapter = new CustomMidwifeAdapter(this);
// Default view is all meals
setListAdapter(mainAdapter);
}
Every time I run this, I get no results.
Thanks in advance for any help
Michael
I can tell you why I think it fails now and I can tell you why I'm very sure it will fail after you sort out the current issue.
It seems that you're trying to use different classes
#ParseClassName("Midwifefirm")
public class Midwifefirm extends ParseObject {
and
ParseQuery query = new ParseQuery("Midwives");
You need to be consistent and use the same name. Either use Midwives or Midwifefirm for both. Let's assume you picked the latter. You're also saying
all that is stored in the user table...wasn't sure if I needed to create new tables.
The query above wants to get all entries of type Midwives. If there's no such type, it'll return nothing. So you have two options:
In you Parse dashboard, reate a class Midwifefirm (don't forget to update the String inside #ParseClassName above) and store your Midwifefirm data in there. You don't need to change your query for this.
Add a column to your ParseUser class, such as type, that you can set to Midwifefirm or whatever if that user is a Midwifefirm or whatever. Then in your query you need to add:
ParseQuery query = new ParseQuery("Midwives");
query.whereEquals("type", "Midwifefirm");
I greatly prefer the former.
Anyway, once your done that, the issue is that you're not using a custom view for this. You're relying on the one provided by Android by default for ListActivity. I am fairly sure it doesn't have any of the fields you're after, so you should create a custom view for this, then at the top of onCreate in your Activity make sure you use it
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_custom_view);
By the way, the following are redundant if you populate then in getItemView anyway:
mainAdapter.setTextKey("practicename");
mainAdapter.setTextKey("education");
mainAdapter.setTextKey("yearsinpractice");
mainAdapter.setTextKey("practicephilosophy");
One final advice: if you're still having issues, set breakpoints and do some investigations first. What you need to check is:
Whether you get anything at all from Parse when you do your query. Your adapter has an useful addOnQueryLoadListener that you may use to check whether anything's been retrieved at all.
If stuff is retrieved successfully, you need to check whether the list view is populated correctly. Again, use breakpoints, this time in getItemView maybe.
I'm going to do a wild guess here using the lovely brainwrecking API help of Parse.com about ParseQueryAdapters
Before continuing, may I mind you that my experience with ParseQueryAdapters is a minimum but I think I have a basic knowledge about them + I have some experience with Parse on its own. ANYHOW,
As an example they use both these
final ParseQueryAdapter adapter = new ParseQueryAdapter(this, "Midwives");
adapter.setTextKey("name");
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
and
// Instantiate a QueryFactory to define the ParseQuery to be used for fetching items in this
// Adapter.
ParseQueryAdapter.QueryFactory<ParseObject> factory =
new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("Midwives");
return query;
}
};
// Pass the factory into the ParseQueryAdapter's constructor.
ParseQueryAdapter<ParseObject> adapter = new ParseQueryAdapter<ParseObject>(this, factory);
adapter.setTextKey("name");
// Perhaps set a callback to be fired upon successful loading of a new set of ParseObjects.
adapter.addOnQueryLoadListener(new OnQueryLoadListener<ParseObject>() {
public void onLoading() {
// Trigger any "loading" UI
}
public void onLoaded(List<ParseObject> objects, ParseException e) {
// Execute any post-loading logic, hide "loading" UI
}
});
// Attach it to your ListView, as in the example above
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);
To start of, the reason why I think nothing is loading inside your list has to do with a little mixup between the initilization of your ParseQueryAdapter and your custom adapter.
You configure the basic adapter, and also initialize a custom adapter but you don't do anything with the custom adapter, tho the custom adapter seems to contain the logics to load your data model.
I think what you're looking for is something like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//initialize main ParseQueryAdapter
mainAdapter = new CustomMidwifeAdapter<ParseObject>(this);
//which keys in Midwife object
mainAdapter.setTextKey("practicename");
mainAdapter.setTextKey("education");
mainAdapter.setTextKey("yearsinpractice");
mainAdapter.setTextKey("practicephilosophy");
// Default view is all meals
setListAdapter(mainAdapter);
}
All you need to pass is the context (aka "this"), and the constructor of your custom class will handle the factory internal
super(context, new ParseQueryAdapter.QueryFactory<Midwifefirm>() {
public ParseQuery<Midwifefirm> create() {
// Here we can configure a ParseQuery to display
// only top-rated meals.
ParseQuery query = new ParseQuery("Midwives");
return query;
}
});
Tho to be honest since you do:
new ParseQueryAdapter<ParseObject>(this, Midwifefirm.class);
I wonder if you'd need to change your "QueryFactory" to
super(context, new ParseQueryAdapter.QueryFactory<Midwifefirm>() {
public ParseQuery<Midwifefirm> create() {
// Here we can configure a ParseQuery to display
// only top-rated meals.
ParseQuery query = new ParseQuery(MidWifefirm.class);
return query;
}
});
Where you pass a class to the the query rather than the tableName, but I could be wrong on that one.
Either way I hope this has helped in some way!
I don't know if I understand the problem correctly, but I have a weird issue. I have list which I am getting from Parse.com server and I filter the data by "tags". Sometimes I change "tags" with DialogFragment and refresh the lists, but after 2-3 change the list is showing wrong data. I have debugged it and it seems that wrong data is being taken from Database, which is weird because in another Fragment window the same method returns correct answers.
Here is how I get list from Parse :
YoursEventsAsync yoursEventsAsync = new YoursEventsAsync(Constants.LIMIT, getActivity());
yoursEventsAsync.asyncResponse = this;
yoursEventsAsync.execute();
Then, in this AsyncTask I am getting data like this :
#SafeVarargs
#Override
protected final ArrayList<Event> doInBackground(ArrayList<Event>... params) {
return ParseAdapter.getInstance().getEventsFromServer(limit, context);
}
And this is my main function responsible for getting sometimes good sometimes bad data :
public ArrayList<Event> getEventsFromServer(int limit, Context context) {
ParseQuery<ParseObject> query = ParseQuery.getQuery("Event");
query.whereContainedIn("tags", DatabaseAdapter.getTagNames(context));
query.setLimit(limit);
query.include("createdBy");
query.orderByDescending("createdAt");
ArrayList<Event> events = new ArrayList<>();
try {
List<ParseObject> parseEvents = query.find();
events = setEventList(parseEvents);
} catch (ParseException e) {
e.printStackTrace();
}
return events;
}
I have debugged the 3rd line and it sometimes works fine and sometimes not.
Here is DatabaseAdapter.getTagNames method :
public static List<String> getTagNames(Context context) {
Realm realm = Realm.getInstance(context);
RealmQuery<Tag> query = realm.where(Tag.class);
RealmResults<Tag> tagResults = query.findAll();
List<String> tags = new ArrayList<>();
for (Tag tag : tagResults) {
tags.add(tag.getName());
}
return tags;
}
As I have said earlier, if I open another fragment, which uses the same method 'getTagNames' it works fine. That's why I think the problem is with context. Is it possible that AsyncTask is somehow remembering the context and retrieveing the old one?
For my Android app, I have subclassed ParseObject to create Food, Pref classes and CustomUser class which extends ParseUser and created a relation "lovers" between 'Food' and 'Users'.
Inside a CustomUser object, I have stored an Pref object using
createWithoutData method in key "pref".CustomUser and its
respective Pref object have one-to-one mapping
So when I want to display all lovers of a particular food in a listview using ParseQueryAdapter,
ParseQueryAdapter<ParseObject> adapter = new ParseQueryAdapter<ParseObject>(getActivity(),
new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery<ParseObject> create() {
ParseQuery<ParseObject> query = food.getRelation("lovers").getQuery();
query.selectKeys(Arrays.asList("pref");
return query;
}
});
adapter.setTextKey(Pref.COLUMN_PROFILE_NAME);
adapter.setImageKey(Pref.COLUMN_PROFILE_PIC_THUMB);
fyi, COLUMN_PROFILE_NAME = "profileName", COLUMN_PROFILE_PIC_THUMB = "profileThumb"
Now the problem is that "pref" is only a reference to the actual object. So when the listView tries to get text and image, it says "ParseObject has no data for this key. Call fetchIfNeeded() to get the data"
My objective is to pass a query to ParseQueryAdapter that will fetch all pref objects nested inside CustomUsers having 'lovers' relation with that particular food.
The parse docs say that 'include' method does not work on relations.
Please help, I have been struggling on this for long now.
To retrieve a relation, I don't believe you can use a query. In your case you would use
ParseRelation<ParseObject> relation = user.getRelation("lovers");
See this documentation
Hope this helps
Below, an example showing off the level of configuration available with this class:
// Instantiate a QueryFactory to define the ParseQuery to be used for fetching items in this
// Adapter.
ParseQueryAdapter.QueryFactory<ParseObject> factory =
new ParseQueryAdapter.QueryFactory<ParseObject>() {
public ParseQuery create() {
ParseQuery query = new ParseQuery("Customer");
//query.whereEqualTo("activated", true);
//query.orderByDescending("moneySpent");
query.include("your key");
return query;
}
};
// Pass the factory into the ParseQueryAdapter's constructor.
ParseQueryAdapter<ParseObject> adapter = new ParseQueryAdapter<ParseObject>(this, factory);
adapter.setTextKey("name");
// Perhaps set a callback to be fired upon successful loading of a new set of ParseObjects.
adapter.addOnQueryLoadListener(new OnQueryLoadListener<ParseObject>() {
public void onLoading() {
// Trigger any "loading" UI
}
public void onLoaded(List<ParseObject> objects, ParseException e) {
// Execute any post-loading logic, hide "loading" UI
}
});
// Attach it to your ListView, as in the example above
ListView listView = (ListView) findViewById(R.id.listview);
listView.setAdapter(adapter);