Query multiple keys in couchbase lite view - android

Hi I am new to couchbase/couchbase-lite and i try to query a view with multiple keys without success. Her is how the map function looks:
public void map(Map<String, Object> doc, Emitter emitter) {
if (doc.get("type").equals("my_type") {
List<Object> keys = new ArrayList<Object>();
keys.add(doc.get("key_1"));
keys.add(doc.get("key_2"));
emitter.emit(keys, null);
}
}
My problem is that i need to query the view either only with key_1 or with a combination of key_1 and key_2 like so
List<Object> keys = new ArrayList<Object>();
keys.add(key_1);
if (key_2 != null) keys.add(key_2);
query.setKeys(keys);
results = query.run()
However the results are always empty. Do i overlook anything?

Two emits doesn't work. If you give a ArrayList in setKeys() method, each key in the List match the each key in emit. If you want to match two keys, add keys ArrayList into another List. Then pass it to setKeys() method. Like this,
List<Object> keys = new ArrayList<Object>();
List<Object> allKeys = new ArrayList<Object>();
keys.add(key_1);
if (key_2 != null) keys.add(key_2);
allKeys.add(keys);
query.setKeys(allKeys);
results = query.run();

This is the solution, We need to add keys into another List<Object> https://github.com/couchbase/couchbase-lite-android/issues/740

Related

Sorting and querying documents in couchbase-lite android

What I want to do is finding all records that match some id and sorted by a name. The data looks something like:
{
type:"receiving",
saleName:"Harshitha",
penId:"7aac88118420858d62f5ea55e22"
}
{
type:"receiving",
saleName:"Tom",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
{
type:"receiving",
saleName:"James",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
I want to get documents with some specific penID sorted by saleName.
Ex:- I want to get documents with this penId ‘81fb1a79526f4e2bdc77aa7d73d’ and sort them by saleName. Like this order:-
{
type:"receiving",
saleName:"James",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
{
type:"receiving",
saleName:"Tom",
penId:"81fb1a79526f4e2bdc77aa7d73d"
}
My view like this,
View view = database.getView("receiving_view");
if (view.getMap() == null) {
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if (document.get("type").equals("receiving") ) {
List<Object> keys = new ArrayList<Object>();
keys.add(document.get("penId"));
keys.add(document.get("saleName"));
emitter.emit(keys, document);
}
}
}, "1.1");
}
return view;
Then I tried to get data like this,
View view = getView("receiving_view");
Query query = view.createQuery();
List<Object> keys = new ArrayList<Object>();
keys.add("81fb1a79526f4e2bdc77aa7d73d");
List<Object> allKeys = new ArrayList<Object>();
allKeys.add(keys);
query.setKeys(allKeys);
query.run();
It’s not working because I passed one key, but their are two keys in the view… But I can’t pass the ‘saleName’ as a key because I want only to sort by ‘saleName’. What is the best way to do this?
Finally I found the solution. I don’t want to use setKeys here, I should use range of keys, not a specific set of keys.
I set startKey to [penID] and endKey to [penID, {}]. The empty map sorts after any other value, so this key range includes all keys that start with penID. I change my data getting method. Now this is what it is looks like,
View view = getView("receiving_view");
Query query = view.createQuery();
query.setStartKey(Arrays.asList("81fb1a79526f4e2bdc77aa7d73d"));
query.setEndKey(Arrays.asList("81fb1a79526f4e2bdc77aa7d73d", new HashMap<String, Object>()));
query.run();

To remove key from hashmap and rearrange keys when used in recycler view

Please any one can help how to remove particular key from hashmap and then rearrange the keys in hashmap accordingly.
Below is my code.
Set<Integer> integerSet = hashMap.keySet();
int removekey = pos;
ArrayList<Integer> integers = new ArrayList<>();
for (Integer integer : integerSet) {
if (integer > removekey) {
integers.add(integer);
}
}
for (Integer integer : integers) {
if (hashMap.containsKey(integer)) {
AddCardPojo pojo = hashMap.get(integer);
pojo.setImagCard(cardImage[integer - 1]);
hashMap.remove(integer);
hashMap.put(integer - 1, pojo);
}
}[![enter image description here][1]][1]
I have attached screenshot of error
You can directly remove a key value pair,you can directly do
hashMap.remove(removeKey);
as for 're arranging keys in hashmap',
it is a data structure which makes no guarantees of order of data.
Check this answer for more
If you need a particular order as per integer, you could use arraylist
Finally it could be done.
Below is my answer.
hashMap.remove(key);
List<AddCardPojo> hashMapsList=new ArrayList<>();
Iterator it = hashMap.entrySet().iterator();
while (it.hasNext()) {
Map.Entry pair = (Map.Entry)it.next();
hashMapsList.add((AddCardPojo) pair.getValue());
}
hashMap = new HashMap<>();
for(int i=0; i<hashMapsList.size();i++){
hashMap.put(i,hashMapsList.get(i));
}

Android Recycler view adapter filter with animation

I am trying to optimize the filter method for RecyclerView Adapter in Android. The list is used as an ArrayList. I have seen this post but they are filtering from the original list every time.
Example: if there are 10 results for String 'a' then user type 'm' , 'am' results are subset of 'a' results(results.size()<=10).
I have three points to ask in this question,
Can I optimize HashMap memory by using ArrayMap? Should I use comma separated positions in String instead of Integer objects array or any way to use int primitive array?
I am not getting any animation in this result, how to get that? (I am using notifyItemInserted still no animation)
How much data should be kept in Hashmap, till 2 characters or it should be according to result list size? I would be glad to know if anything can be done better in this code other than these points.
In below code, mList is used in onBindViewHolder method. copyList always contains all data(no insertion or deletion is done on that).
class MyFilter extends Filter {
/**
* 1. check do we have search results available (check map has this key)
* 2. if available, remove all rows and add only those which are value for that key (string)
* 3. else check do we have any key available starting like this, s=har, already available -ha then it can be reused
*
* #param constraint
*/
#Override
protected FilterResults performFiltering(CharSequence constraint) {
//Here you have to implement filtering way
final FilterResults results = new FilterResults();
if (!mSearchMap.containsKey(constraint.toString())) {
String supersetKey = getSupersetIfAvailable(mSearchMap, constraint.toString());
if (supersetKey == null) {
List<Integer> foundPositions = doFullSearch(copyList, constraint.toString());
mSearchMap.put(constraint.toString(), foundPositions);
} else {
List<Integer> foundPositions = filterFromSuperset(copyList, mSearchMap.get(supersetKey), constraint.toString());
mSearchMap.put(constraint.toString(), foundPositions);
}
}
return results;
}
private String getSupersetIfAvailable(Map<String, List<Integer>> mSearchMap, String s) {
Set<String> set = mSearchMap.keySet();
List<String> list = new ArrayList<>(set);
Collections.sort(list);
Collections.reverse(list);
for (String c : list) {
if (s.startsWith(c)) {
return c;
}
}
return null;
}
private List<Integer> filterFromSuperset(List<WeekWorkBean> list, List<Integer> supersetResults, String s) {
List<Integer> results = new ArrayList<>();
String lowerS = s.toLowerCase();
for (int i = 0; i < supersetResults.size(); i++) {
if (list.get(supersetResults.get(i)).getEmpName().toLowerCase().startsWith(lowerS)) {
results.add(supersetResults.get(i));
}
}
return results;
}
private List<Integer> doFullSearch(List<WeekWorkBean> list, String s) {
List<Integer> results = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).getEmpName().toLowerCase().startsWith(s.toLowerCase())) {
results.add(i);
}
}
return results;
}
#Override
protected void publishResults(CharSequence constraint, FilterResults results) {
// here you can use result - (f.e. set in in adapter list)
mList.clear();
notifyDataSetChanged();
List<Integer> res = mSearchMap.get(constraint.toString());
int j = 0;
for (Integer i : res) {
mList.add(copyList.get(i));
notifyItemInserted(j++);
}
}
}
Check this out
https://medium.com/#iammert/using-diffutil-in-android-recyclerview-bdca8e4fbb00#.ehc0gaijt
DiffUtils is what are you looking for. You can use it in Rx chain to move it out of mainThread for a large data.
here is a example
https://medium.com/#nullthemall/diffutil-is-a-must-797502bc1149#.yg35y9q9b
To give an answer for your 2nd point you can try this:
notifyItemRangeChanged(pos, ItemList.size());
HashMap is a Map, there are also TreeMap, LinkedHashMap and Hashtable. each of them has own features and interface is Map, not Collection. You can also use other data structures, like Treeset, HashSet, ArrayList, LinkedList and etc. These structures comes from Set and List interface, which extends to Collection interface. You can use each of them.
If you insert any object to your collection, use notifyItemInserted(int position), if you delete any object use notifyItemRemoved(int position), if you update any object use notifyDataSetChanged(). Be careful about equality of your collection length and adapter view count.
You can store parameter in maps how much you want. There is not any limitation. But you should choose best Collection for you, set, list or map.

Sorting a JSONArray in java

I'm working on an API where I'm getting a JSONArray in which there reside numerous JSONobjects containing around 10 KeyValue pairs. One of them is date: 10-3-2015. I want to use this JSONArray in a sorted manner according to the date value. I've tried a various ways including TreeMap but no success yet.
A short piece of code or a thorough idea will do the work for me.
Thanks.
EDIT:
You can do sorting easily if you use model to hold element in JSONArray.Let's say you have have model Person and JSON array contains list of persons then you can traverse JSONArray and make list of persons as follows:
List<Person> persons=new ArrayList<>();
if(jsonArray!=null){
for(JSONObject person:jsonArray){
Person p=new Person();
//set properties
//.............
//add it to persons
persons.add(p);
}
}
Now you can sort list of persons as follows:
Collections.sort(persons, new Comparator() {
public int compare(Object obj1, Object obj2) {
if (!(obj1 instanceof Person) || !(obj2 instanceof Person)) {
return -1;
}
Person p1 = (Person)obj1;
Person p2 = (Person)obj2;
return p1.getAge() -p2.getAge();
}
});
Now you can use this sorted list "persons".

Parsing JSON then adding multiple strings to an ArrayList

Currently working on an app that takes results from a search, parses the JSON object returned, and then adds the resulting pieces into a few ArrayLists within a class created called VenueList.
Here is the method that receives the results from the service and parses the JSON:
private static List<String> getResultsFromJson(String json) {
ArrayList<String> resultList = new ArrayList<String>();
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
resultList.add(result.getString("text"));
}
}
catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
return resultList;
}
What results of this becomes a List variable call mResults (to clarify: mResults = getResultsFromJson(restResult);. That is then used, among other places, in the following loop that puts the results into an ArrayAdapter that is used for displaying them in a ListFragment:
for (String result : mResults) {
VenueList.addVenue(result, "HELLO WORLD");
adapter.add(result);
}
I also add the result to a class called VenueList that manages the results and makes them accessible for multiple views. It essentially just holds multiple ArrayLists that hold different types of details for each venue returned in the search. The method I use to add a venue to VenueList is below (and you can see it used in the for loop above):
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
I want the addVenue method to be able to take multiple arguments and update the VenueList class. Yet, when I call the addVenue method in the for loop, I can only pass it String result (from the parameters of the loop) and can't figure out how to pass it a second argument (which should also come from the JSON parsed by getResultsFromJson) so I've used "HELLO WORLD" as a placeholder for now.
I realize getResultsFromJson only has one list returned. I need to be able to take multiple elements from the JSON object that I parse, and then add them to VenueList in the right order.
So my questions are:
1) Given the getResultsFromJson method and the for loop, how can I use the addVenue() method as designed? How do I parse multiple elements from the JSON, and then add them to the VenueList at the same time? I plan on adding more arguments to it later on, but I assume if I can make it work with two, I can make it work with four or five.
2) If that's not possible, how should the getResultsFromJson, the for loop, and the addVenue method be redesigned to work properly together?
Please let me know if you need more detail or code - happy to provide. Thank you!
EDIT - Full VenueList class:
public class VenueList {
private static ArrayList<String> venueNames;
private static ArrayList<String> venueGeos;
public VenueList() {
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
}
public static void addVenue(String name, String geo) {
venueNames.add(name);
venueGeos.add(geo);
}
public static String getVenueName(int position) {
return venueNames.get(position);
}
public static String getVenueGeo(int position) {
return venueGeos.get(position);
}
public static void clearList() {
venueNames.clear();
venueGeos.clear();
}
}
Clarification: I will have additional ArrayLists for each element of data that I want to store about a venue (phone number, address, etc etc)
1) I don't think methods getResultsFromJson(String json) and addVenue(String name, String geo) fit your needs.
2) I would consider rewriting method getResultsFromJson(String json) to something like this:
private static SortedMap<Integer, List<String>> getResultsFromJson(String json) {
Map<Integer, String> resultMap = new TreeMap<Integer, String>();
//...
return resultMap;
}
where the number of keys of your map should be equal to the number of objects you're extracting info, and each one of them will properly have their own list of items just in the right order you extract them.
With this approach you can certainly change your logic to something like this:
// grab your retuned map and get an entrySet, the just iterate trough it
SortedMap<Integer, String> result = returnedMap.entrySet();
for (Entry<Integer, String> result : entrySet) {
Integer key = result.getKey(); // use it if you need it
List<String> yourDesiredItems = result.getValue(); // explicitly shown to know how to get it
VenueList.addVenue(yourDesiredItems);
}
public static void addVenue(List<String> yourDesiredItems) {
// refactor here to iterate the items trough the list and save properly
//....
}
EDIT -- as you wish to avoid the go-between map i'm assuming you need nothing to return from the method
First i'm providing you with a solution to your requirements, then i'll provide you with some tips cause i see some things that could smplify your design.
To save VenueList things directly from getResultsFromJSON do something like this:
private static void getResultsFromJson(String json) {
try {
JSONObject resultsWrapper = (JSONObject) new JSONTokener(json).nextValue();
JSONArray results = resultsWrapper.getJSONArray("results");
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
//FOR EXAMPLE HERE IS WHERE YOU NEED TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then...
VenueList.addVenue(name, geo, ..., etc);
}
} catch (JSONException e) {
Log.e(TAG, "Failed to parse JSON.", e);
}
}
This implies that your addVenue method should know receive all params needed; as you can see this is just a way (that you can consider a workaround to your needs), however as i don't know all requirements that lead you to code this model, i will point to a few things you might consider:
1. If there's a reason for VenueList class to use everything static, consider doing this:
static{
venueNames = new ArrayList<String>();
venueGeos = new ArrayList<String>();
//....
}
private VenueList(){
}
This way you won't need to get an instance every time and also will avoid null pointer exceptions when doing VenueList.addVenue(...) without previous instantiation.
2. Instead of having an ArrayList for every characteristic in VenueList class consider defining a model object for a Venue like this:
public class Venue{
String name;
String geo;
//... etc
public Venue(){
}
// ... getters & setters
}
then if you need that VenueList class you will just have a list o Venue objects (List<Venue>), this means that instead of calling the method addVenue, you will first create a brand new instance of Venue class and will call the setter method of each characteristic, as an example of the refactored for loop from the workaround i provided you you'd be using something like this:
List<Venue> myListOfVenues = new ArrayList<Venue>();
for (int i = 0; i < results.length(); i++) {
JSONObject result = results.getJSONObject(i);
// THIS WOULD REMAIN THE SAME TO EXTRACT INFO
String name = result.getString("name");
String geo = result.getString("geo");
// and then instead of calling VenueList.addVenue(name, geo, ..., etc)...
Venue v = new Venue();
v.setName(name);
v.setGeo(geo);
// ...etc
myListOfVenues.add(v);
}
// Once you're done, set that List to VenueList class
VenueList.setVenueList(myListOfVenues);
So VenueList class would now have a single property List<Venue> venueList; and would suffer minor tweeks on methods getVenueName, etc... and everything would be more readable... i hope this helps you to get another approach to solve your problem, if i still don't make my point let me know and i'll try to help you out...

Categories

Resources