mongoose nodejs sort by data based on another collection - android

I am making an app with NodeJS and MongoDB using RESTFUL API. Android on the client side.
I have two collections:
Images which contain
user id
title,description, image string etc
array of tags (tags: [{name: blah}]
And User collection:
user name, email, password etc
array of tags ( tags: [{name:blah, score: 2}]
For every image that a user adds I add all the tags of the image to the user with score 2 if they don't exist or increase the score by 2 if the tag exists for the user.
I want to get all the images sorted by the user's score - for instance if the user has tags like that - {name: baseball, score:2},{name: soccer, score:4}
the image with soccer tag will be first and after that the image with baseball tags.
I tried doing that on the client side(Java) and it requires a lot of loops and inefficient code.
However, using GET I can't send the user's data (the tags with the score).
What is the correct way to do that?
Edit: I managed to do that by populating the user_id field in images schema.
Now I can get all images with all the user's data.
On the client side I am sorting the images by their user's score - looping the user's tags by their score from the highest value to the lowest and adding each image to a new list.
Then I add the rest of images to the temporary list and create the recycler view with it:
List<UserTags> sortedUserTagsListByScore = userTags;
Collections.sort(sortedUserTagsListByScore, new Comparator<UserTags>() {
#Override
public int compare(UserTags lhs, UserTags rhs) {
return rhs.getScore().compareTo(lhs.getScore());
}
});
// reverse user tags for ascending order
// Collections.reverse(userTags);
// loop all user tags
for (int i = 0; i < userTags.size(); i++) {
// loop all images
for (int j = 0; j < imagesArray.size(); j++){
// loop all tags of an image
for (int k = 0; k < imagesArray.get(j).getTags().size(); k++) {
// checks if the tag of the image equals the user tag
if (imagesArray.get(j).getTags().get(k).toString().equals(userTags.get(i).getName())){
// for debugging
// imagesArray.get(j).setUpvotes(userTags.get(i).getScore());
tempImagesArray.add(imagesArray.get(j));
Log.v("sort","tag found :" + imagesArray.get(j).getTags().get(k) + " score: " + userTags.get(i).getScore());
// remove image and insert false image
imagesArray.remove(j);
imagesArray.add(j,new Image("REMOVE"));
break;
}
}
}
}
// delete images that added to tempImagesArray
for (Image image :
new ArrayList<>(imagesArray)) {
if (image.getId().equals("REMOVE"))
imagesArray.remove(image);
}
// sort images without user tag by upvotes
Collections.sort(imagesArray, new Comparator<Image>() {
#Override
public int compare(Image lhs, Image rhs) {
return rhs.getUpvotes().compareTo(lhs.getUpvotes());
}
});
// add images without user tag to sorted images list
tempImagesArray.addAll(imagesArray);
imagesArray = tempImagesArray;
createCards();

Related

Looping out JSON Array using ArrayList

I am trying to learn retrofit and I have made successful attempts at posting data and now I am trying to retrieve JSON array which looks as follows:
{
"result": "success",
"message": "All Questions Have Been Selected",
"question": {
"all_question_ids": ["1","2","3"]
}
}
I am using the following getter
public ArrayList getAll_question_ids(){
return all_question_ids;
}
I am retrieving using Retrofit as follows
if (resp.getResult().equals(Constants.SUCCESS)) {
SharedPreferences.Editor editor = pref.edit();
Log.d("Question_IDs", "getAllQuestionID() = " + response.body().getQuestion().getAll_question_ids() );
editor.putString(Constants.All_QUESTION_IDS,((resp.getQuestion().getAll_question_ids().toString())));
editor.apply();
}
progress.setVisibility(View.INVISIBLE);
It is here that I am stuck, as I am retrieving the array ok but I am unsure how to loop out the Array which is now stored in Shared Preferences.
When I place a toast to show me how the IDs are coming across, my toast confirms the data as [1,2,3]
The goal is to add a dynamic button and the individual ID, i.e button 1, button 2 etc every-time the loop is iterated.
I have tried the following:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
for (int i =0; i < questionNumber.length(); i++) {
try {
/*Dynamically create new Button which includes the question name
*/
AppCompatButton btn_question = new AppCompatButton(getActivity());
/*LayoutParams (int width, int height,float weight)
As LayoutParams is defaulted in px, I have called a method called dpToPX to make sure
the dynamically added EditText is the same size on all devices.
*/
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(dpToPx(280), dpToPx(45), 1);
btn_question.setBackgroundColor(Color.parseColor("#3B5998"));
btn_question.setTextColor(Color.WHITE);
// btn_question.setText(String.valueOf(x));
btn_question.setText("Question "+ pref.getString(Constants.All_QUESTION_IDS,""));
btn_question.setGravity(Gravity.CENTER);
//generate unique ID for each new EditText dynamically created
View.generateViewId();
//Log.d("TEST VALUE", "Question1 generated ID = " + btn_question.generateViewId());
params.setMargins(0, dpToPx(10), 0, dpToPx(10));
btn_question.setPadding(0, 0, 0, 0);
btn_question.setLayoutParams(params);
allEds.add(btn_question);
mLayout.addView(btn_question);
} catch (Exception e) {
Log.d(TAG, "Failed to create new edit text");
}
}
However the above is adding the value as it appears in the array e.g [1,2,3] which is obviously not what I want.
I have added a photo in case my explanation isn't clear. I want a button with 1 number added to it each time the loop iterates but I am unable to figure this out.
I have looked through lots of resource but cannot find an answer that is relevant to my problem, although, if there is, I am not familiar enough to recognise a similar issue.
If someone can offer some assistance, I would appreciate it!
When you call editor.putString(Constants.All_QUESTION_IDS,((SOMETHING.toString())));, what is actually stored depends on the implementation of the toString method in the type of SOMETHING (in this case String[]). So avoid doing that. Instead, since you're already using Gson or Jackson (or others), store the question_idsas JSON:
final String jsonIds = gson.toJson (resp.getQuestion().getAll_question_ids());
editor.putString(Constants.All_QUESTION_IDS, jsonIds);
Your actual stored value no longer depends on the implementation of something that you don't control (String[].toString). It is a valid JSON array and regardless of what tool/library you use to read it back, it's valid.
Now, to read back the stored data:
final String storedJson = pref.getString(Constants.All_QUESTION_IDS, null);
if (null == storedJson) {
// TODO: No question ids found
}
final String[] ids = gson.fromJson (storedJson, String[].class);
for (int i = 0; i < ids.length; i++) {
// make your buttons
}
This is a problem of saving and then reading out a List of items (in this case, String instances).
You've chosen to save the list by calling editor.putString() with a value of getAll_question_ids().toString(). That toString() call is going to return a string representation of your list, or, in other words, a String instance with the value [1, 2, 3]. At this point, you no longer have a List proper, but a String that looks like a list.
This is all technically fine, but it means you have to take this into account when you're trying to read out that list.
You've written this to read the list back out:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
Once this line executes, questionNumber will be a String instance with the value [1, 2, 3]. Again, this is fine, but now we come to the key point: we have to convert this String back into a List.
If you know for sure that the values in this list won't have commas in them, you can do it easily:
Trim the braces off the string using substring()
Create a String[] using split()
Convert your array to a list using Arrays.asList() (you could even skip this step since iterating over an array is just as easy as iterating over a list)
Put that together and you get:
String questionNumber = pref.getString(Constants.All_QUESTION_IDS, "");
questionNumber = questionNumber.substring(1, questionNumber.length() - 1);
String[] array = questionNumber.split(", ");
List list = Arrays.asList(array);
At this point, you can iterate over your array or list:
for (String value : list) {
...
btn_question.setText("Question " + value);
...
}

parse cloud; How to write a query to get all data in a particular column

I am apologize for this type Question. I am first time use Cloud Code in parse so I have No idea how to get data in parse through Cloud code. If any idea then suggest me. I have check many example but I have not found in my problem.
My parse data base is like this..
userId game1score game2score game3score gender
xcvgfs1 300 200 100 man
sfdgdh 500 600 300 man
like this parse data base many user are playing game and score the game.
My problem is how to get all user score in game1score ya other game score and compare to current user score and find the Rank of current user.
Thanks for helping..
Call the cloud code function is like this in my activity..
Map<String, String> map = new HashMap<String, String>();
map.put(" game1score", "300");
ParseCloud.callFunctionInBackground("check_duplicate",map,new FunctionCallback<Object>() {
#Override
public void done(Object o, ParseException e) {
if(e==null){
Log.e("String",""+o) ;
}else{
Log.e("error",e.getMessage()) ;
}
}
});
return always null or 0
As far as I understand from your explanation, you want to extract the rank number of current user via using the Parse Score table where you record 3 different game scores (gameScore1, gameScore2, gameScore3). You have already write the Cloud code trigger function. So the cloud code that you can use is below;
Parse.Cloud.define("rank", function(request, status)
{
var result = [];
var processRankCallback = function(res) {
result = result.concat(res);
if (res.length === 1000)
{
process(res[res.length-1].id);
return;
}
//All object that is greater than the given user score
status.success(result.length);
}
var processRank = function(skip)
{
var query = new Parse.Query("Score");
var userScore = request.params.userScore;
var gameType = request.params.gameType;
if (skip) query.greaterThan("objectId", skip);
query.limit(1000);
query.ascending("objectId");
query.find().then(function querySuccess(res)
{
var innerResult = [];
for(var i = 0 ; i < res.length;i++)
{
//var gameScore1 = res[i].get("gameScore1");
//var gameScore2 = res[i].get("gameScore2");
//var gameScore3 = res[i].get("gameScore3");
//var total = gameScore1+gameScore2+gameScore3;
var total = res[i].get(gameType);
if(userScore < total) innerResult.push(res[i]);
}
processRankCallback(innerResult);
}, function queryFailed(reason)
{
status.error("Error:" + error.code + " Message" + error.message);
});
}
processRank(false);
});
Actually, finding the rank means that query the Score table and count the entry where the game scores all total is larger than your current user total game score. To implement this you can use the countQuery however Parse countQuery can fail or show incorrect result when your table entry is larger than 1000. So, instead of using count query, you can walk through the entire table and find all entries that have larger game score than your current user. In above code, I assume that you have 3 different game scores and all have valid number (not undefined). You can modify the code for your own purposes. The end result will generate a number which is actually the number of entry in Score table that has larger game score total than your current user game scores total.
For example I have a Score table with column gameScore1 and 3 entries where the scores are 600, 200 and 100. I call the Cloud function with below parameters hash table;
HashMap<String, String> params = new HashMap<String, String>();
params.put("userScore", "150");
params.put("gameType", "gameScore1");
//Call Parse cloud function
The response will be 2 which actually means that there are two entries that has gameScore1 which is larger than 150. Hope this helps.
Regards.

ArrayList not deleting properly

I have a screen where the user selects items he/she wants deleted, then I store his/her choices into an integer arrayList (based on which positions they clicked on the listView).
I then pass the items that they want deleted to a function where I actually delete them from my hashtable that holds all the information. For some reason though, it's just NOT deleting from the hashtable. I've tested and looked at all the variables I'm using to access the data and they are correct. I'm not sure why it's not removing what I tell it to..
Here is the function:
for (Entry<Integer, ArrayList<Deck>> i : listOfDecks.entrySet()) {
for (int p = 0; p < i.getValue().size(); p++) {
if (i.getValue().get(p).getTitle().equals(deckTitle)) {
for (int z = 0; z < deletedItems.size(); z++) {
listOfDecks.get(i.getKey()).get(p).getDeck().remove(deletedItems.get(z));
}
}
}
}
deletedItems is the arrayList that holds what the user has selected as their items they want deleted.
What I see is that you are calling Deck.remove(int) so you're not removing from a hashtable, but from a deck.
What does this method remove(int) of the class Deck do?.

For-loop not working the way i want it to

I have a extremely minor issue that I can't seem to figure out. I'm trying to extract data based on a type of value from an ArrayList> and place it into another ArrayList. The issue is that the for-loop only runs once, which in this case i need it to traverse the entire array and then place the data into the unSuppressedData arraylist.
Below is the for-loop:
for (int x = 0; x < suppressedStatus.length; x++) {
for (int i = 0; i < availData.size(); i++) {
Hashtable<String,String> checkAvail = availData.get(i);
String itemStatus = checkAvail.get("loanStatus");
if (unSuppressedData.contains(checkAvail) == false) {
if (!(itemStatus.equals(suppressedStatus[x]))) {
Log.d("Item Status", itemStatus);
Log.d("Suppressed Status", suppressedStatus[x]);
unSuppressedData.add(checkAvail);
//break;
}
}
}
}
suppressedStatus is a String array
availData is the arraylist i want to extract data from
unSuppressedData is the arraylist i want to place the data in
I believe that it only runs once is due to this line of code:
if (unSuppressedData.contains(checkAvail) == false) {
But i need to this line to check whether my unSuppressdData has the data, if no then will add the data from availData arraylist into unSuppressedData arraylist.
Could it be that i'm writing this piece of code wrongly? Appreciate any insights shed on this.
A good collection type for this sort of thing is the LinkedHashSet. Because it's a set, each element can only be added once. Being a hash, the contains test is quick. Being 'linked' the resulting set is iterated in insertion order.

can't get the text from an autocomplete

I have to create an app in android with a database.In that database I have a predefined list of products.
Now,the thing is that my ap has to offer to the user the posibility to introduce in that list some other products which are not in the list.
To this end, I've created an autocomplete text view in which I introduce a new product and I take the text fro autocomplete and I have to write it in the database
Now,my problem is that when I display the products that I've introduced in the database,the toast text that I use to display what I have in the database it shows me nothing next to "product......".
Now,that may be because when I try to get the text from the autocomplete I get nothing in return?
This is how I read from autocomplete:
mItem = (AutoCompleteTextView) findViewById(R.id.todo_edit_item);
String nou=mItem.getText().toString();
And then I compare nou(which is what I wrote in the autocomplete) with what I have predefnied in the list,so if it is a new product(which was not in the list already) the I add it in the database:
for(int i = 0; i < l; i++)
{
if (nou!=fruits[i])
t=true;
else t=false;
}
if (t==true)
{
db.insertTitle(nou);
fruits=db.getAllfromDB("Fruits","fruit");
l=l+1;
}
Anyone any ideas of what I'm doing wrong in here cause I can't figure out.I'lll be here for further details.Thank u in advance:)
You compare strings using != instead of using !nou.equals(fruits[i]). also you compare to all elements in array each time, since you so t is always the value of the comparison to the last element in the array whether a match was found or not.
It should be written like that:
t = true;
for(int i = 0; i < l; i++)
{
if (nou.equals(fruits[i]))
{
t=false;
break;
}
}
if (t==true)
{
db.insertTitle(nou);
fruits=db.getAllfromDB("Fruits","fruit");
l=l+1;
}

Categories

Resources