I am now working on CloudCode, and would like to retrieve the number of items in the Parse Database that is greater than certain criteria (i.e. an inputting parameter).
Parse Cloud Code:
Parse.Cloud.define("query_num_greater_than_local", function(request, response)
{
var DB = Parse.Object.extend("Recording_db");
var query= new Parse.Query(DB);
query.greaterThan("Ref_int",1234);
query.find(
{
success: function(results)
{
console.log("received " + results.length + " result(s)");
response.success("done" + results.length);
},
error: function(error)
{
console.log("error: " + error);
}
});
});
Android code:
ParseCloud.callFunctionInBackground("query_num_greater_than_local", new HashMap<String, Object>(), new FunctionCallback<String>()
{
public void done(String result, ParseException e)
{
if (e == null)
{
tv1.setText(""+result);
}
else
{
tv1.setText("ParseException"+e);
}
}
});
Question:
While the above codes return a correct count of items greater than 1234, I would like to ask whether can 1234 be replaced as a parameter? i.e. query for a result based on an inputting variable query criteria, say become query.greaterThan("Ref_int", 2345)?
If then, how could this variable inputting criteria be applied to the codes? Many thanks!
Related
I am making an app that will listen to new document addition to Firestore collection. I have tried look at Firestore documentation, but doesn't work for my specific problem.
Here is my code listen to document updata
FirebaseFirestore.getInstance().collection("users/" + companyID + "/trips").addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot querySnapshot, #Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
if (!querySnapshot.isEmpty()){
for (QueryDocumentSnapshot qds : querySnapshot){
tripList.add(qds.getId());
}
showTripList();//update trip list view
}
}
});
Show the list to the ListView
public void showTripList() {
ListView tripListView = findViewById(R.id.tripList);
if (tripList.size() != 0) {
ArrayAdapter arrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, tripList);
tripListView.setAdapter(arrayAdapter);//show trip list on screen
} else {
TextView noTripTxt = findViewById(R.id.noTripTxt);
noTripTxt.setVisibility(View.VISIBLE);//show "no trip has been made yet" text to user
}
}
The logcat shows NullPointerException at this two line
FirebaseFirestore.getInstance().collection("users/" + companyID + "/trips").addSnapshotListener(new EventListener<QuerySnapshot>()
tripList.add(qds.getId());
Here the code that is work for me
FirebaseFirestore.getInstance().collection("users/" + companyID + "/trips")
.addSnapshotListener(new EventListener<QuerySnapshot>() {
#Override
public void onEvent(#Nullable QuerySnapshot value, #Nullable FirebaseFirestoreException e) {
if (e != null) {
Log.w(TAG, "Listen failed.", e);
return;
}
tripList.clear();//clear the ArrayList, because this method get all the document id instead of
//the one that just created
for (QueryDocumentSnapshot doc : value) {
if (doc.getId() != null){
tripList.add(doc.getId());//store the document IDs to ArrayList
Log.d(TAG, "Retrieved data: " + doc.getId());
}
}
showTripList();//show trip name to listView
}
});
The code you shared seems to try and listen to the trips subcollection of a specific companyId. But the way you build the path to that collection seems suspicious:
collection("users" + companyID + "trips")
The total path should be users/${companyID}/trips, so it's more likely that the code should be:
collection("users/" + companyID + "/trips")
Without the / your code is listening to a top-level collection users${companyID}trips, which doesn't exist. So that would explain why you're not getting any results.
Note that you can easily prevent such string concatenation problems, by using the more explicit API variant:
collection("users").doc(companyID).collection("trips")
While that last variant is a bit longer, it removes the chance of making simple string concatenation mistakes.
With the collection path fixed, your code will be listening for the data in a subcollection. So it will match multiple documents, and get a QuerySnapshot as shown in the documentation on listening to multiple documents in a collection.
I want to fill an ArrayList with the results I get back from a Parse query. When I get the results I add them to the ArrayList and print the ArrayList size to the console to make sure the results are added, which is succesful, but when I return the ArrayList it's empty. Can anyone explain to me why this happens?
public ArrayList<ParseObject>findAllGroupByUserId(ParseUser userId){
//TODO hier uit db halen alle groupen van user
final ArrayList<ParseObject> groups = new ArrayList<>();
ParseQuery<Group_user> query = ParseQuery.getQuery("Group_user");
query.whereEqualTo("user_id", userId);
query.findInBackground(new FindCallback<Group_user>() {
#Override
public void done(List<Group_user> objects, ParseException e) {
if (e == null) {
for (Group_user group : objects) {
Log.e("SUCCESS", group.getObjectId() + " , " + group.getGroup_id().getObjectId());
ParseObject g = new Group();
groups.add(g);
}
System.out.println(groups.size() + " :Done method"); //THIS RETURNS 2
} else {
Log.e("ERROR", "message: " + e);
}
Log.e("SUCCESS", "we have " + groups.size() + " results");
}
});
System.out.println(groups.size() + " :return"); // THIS RETURNS 0
return groups;
}
Because findInBackground() runs asynchronously on a different thread. You need to execute your remaining logic from the done() call back to get the populated array.
Think of it like this:
Thread 1 -> invokes findInBackground() -> thread one is running -----------> group is empty until Thread 2 finishes
Thread 2 spawned -> reaches out to server and gets query results -> invokes done call back on Thread 1 (now you have the data ready)
So I'm assuming that Group_user is a subclass of ParseObject that you've already defined. Since the findInBackground is async, you should change logic of the calling of the function to async too. Instead of returning list of objects like you were before, do all the logic in the done function of the query, no need to return.
public void findAllGroupByUserId(ParseUser userId) {
ParseQuery<Group_user> query = ParseQuery.getQuery("Group_user");
query.whereEqualTo("user_id", userId);
query.findInBackground(new FindCallback<Group_user>() {
#Override
public void done(List<Group_user> groups, ParseException e) {
if (e == null && groups != null) {
for (Group_user group : groups) {
// perform all logic here
}
} else {
Log.e("Find Callback", "Oh no! Query failed!");
}
}
});
}
I'm using Parse and I'm doing a query to fetch a table .
As you can see in the code below, the list LOCALparseQuestionList is populated correctly during the for loop inside the findInBackground. Once it's done, the LOCALparseQuestionList is empty (the log prints 0 size and I see the same when using the debugger).
How should I fetch correctly the data and populate my LOCALparseQuestionList?
public List<QuestionStruct> getParseAllQuestions() {
final List<QuestionStruct> LOCALparseQuestionList = new ArrayList<QuestionStruct>();
// Select All Query
ParseQuery<ParseObject> questionQuery = ParseQuery.getQuery("triviaQuestions");
questionQuery.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> allQuestions, ParseException e) {
if (e == null) {
parseQuestionList = allQuestions;
Log.d(TAG, "Retrieved " + allQuestions.size() + " All questions");
for (ParseObject qu : allQuestions) {
QuestionStruct currentQuestion = new QuestionStruct();
currentQuestion.setID(qu.getInt("id"));
currentQuestion.setQuestion(qu.getString("question"));
currentQuestion.setCorrectAnswer(qu.getString("correct"));
currentQuestion.setPossibleAnswer(qu.getString("wrong_1"));
currentQuestion.setPossibleAnswer(qu.getString("wrong_2"));
currentQuestion.setPossibleAnswer(qu.getString("wrong_3"));
currentQuestion.setPossibleAnswer(qu.getString("correct"));
LOCALparseQuestionList.add(currentQuestion);
Log.d(TAG, "Retrieved " + LOCALparseQuestionList.size() + " LOCALparseQuestionList ");
}
} else {
Log.d(TAG, "Error: " + e.getMessage());
}
}
});
Log.d(TAG, "questionList size: " + LOCALparseQuestionList.size());
return LOCALparseQuestionList;
}
Its a the number one misunderstanding about asynchronous functions: the code underneath the find function does not run after the find function. It runs before it.
The last log statement in the function logs, and the return statement returns an empty list, because that list is populated later, after the find is done and the results are returned. Anything you do that depend on LOCALparseQuestionList being populated must be done within the find's callback.
I'm trying to get Parse server date and time but I get to know the only way is to create or update an object then retrieve the value of updatedAt.
My class
//There is only one data/object in this class
Class Test{
int times
};
My cloud code
increment of value "times" is to get current server date and time via getUpdatedAt();
Parse.Cloud.define("updateTimes", function(request, response) {
var test = Parse.Object.extend("Test");
var query = new Parse.Query(test);
query.first({
success: function(results) {
results.increment("times");
results.save();
response.success("success updated");
},
error: function() {
response.error("test lookup failed");
}
});
});
My calling at android studio
//Call updateTimes function at cloud code
ParseCloud.callFunctionInBackground("updateTimes", new HashMap<String, Object>(), new FunctionCallback<String>() {
public void done(String result, ParseException e) {
if (e == null) { //success }
}
});
//Get date and time from server
ParseQuery<ParseObject> query = ParseQuery.getQuery("Test");
query.getInBackground("i6hmOEItvI", new GetCallback<ParseObject>() {
public void done(ParseObject object, ParseException e) {
if (e == null) {
// success
serverDate = object.getUpdatedAt();
Format formatter = new SimpleDateFormat("dd-MM-yyyy HH:mm:ss");
date = formatter.format(serverDate);
Log.d("ServerDate",date);
}
});
My problem is the serverDate retrieved from objectId is not correct. The date retrieved is always the older one. However, the updateAt field in database is successfully updated.
I have called ParseCloud.callFunctionInBackground before calling query object.getUpdatedAt();.
Any has any idea why the date I get is not the latest?
It seems a waste to create or touch data just to see what date stamp was written. Why not return a date directly:
Parse.Cloud.define("serverDateTime", function(request, response) {
response.success({dateTime: new Date()});
});
This is doing my head in. I got this working in iOS in about 10 mins. Clearly I'm missing something. I'm simply trying to pull data out of parse.com into a textfield. I have found lots of examples but none explaining why it's not working correctly. Below is the code pulled from parse.com site and jiggyed with. Incidentally it's wigging out on totemList.getString particularly the "getString" part.
ParseQuery<ParseObject> query = ParseQuery.getQuery("Birds");
query.whereEqualTo("totemName", "Pigeon");
query.findInBackground(new FindCallback<ParseObject>() {
public void done(List<ParseObject> totemList, ParseException e) {
if (e == null) {
Log.d("score", "Retrieved " + totemList.size() + " scores");
String totemDesc = totemList.getString("totemDesc");
//Get the Totems Description
TotemDescription = (TextView)findViewById(R.id.animalDesc);
TotemDescription.setText(totemDesc);
} else {
Log.d("score", "Error: " + e.getMessage());
// something went wrong
TotemDescription = (TextView)findViewById(R.id.animalDesc);
TotemDescription.setText("not bob");
}
}
});
List<> does not have a getString() method.
List<ParseObject> totemList
Perhaps what you wanted to do was to iterate over your list of ParseObject get all the descriptions:
String descriptions = null;
for (ParseObject totem : totemList) {
if (descriptions == null) {
descriptions = totem.getString("totemDesc");
} else {
descriptions = descriptions + ", " + totem.getString("totemDesc");
}
}
Something like that. Then set the resulting string as text of your text field
TotemDescription.setText(descriptions);
If you have more than one ParseObject in your List<> your text will be something like:
Pigeon Totem, Another Pigeon Totem