Couchbase Lite: reading document vs querying data - android

I'm switching an Android project to using Couchbase Lite, and I'm confused with ways for fetching the data from the database.
I have a document, which contains only one property:
Map<String, Object> properties = new HashMap<String, Object>();
properties.put("data_key", json);
Document document = database.getDocument("data_doc_id");
document.putProperties(properties);
The next my step is getting the stored data from the database. I found two ways:
The first approach is reading the document
Document doc = database.getDocument("data_doc_id");
String json = (String) doc.getProperty("data_key");
The second one is querying
View view = database.getView("data_json");
view.setMap(new Mapper() {
#Override
public void map(Map<String, Object> document, Emitter emitter) {
if ("data_doc_id".equals(document.get("_id")) {
String json = (String) doc.getProperty("data_key");
emitter.emit("data_key", json);
}
}
}, "1.0");
QueryEnumerator queryEnumerator = view.createQuery().run();
String dataJson = "";
for (QueryRow queryRow : run) {
if ("data_key".equals(queryRow.getKey()) {
json = (String) queryRow.getValue();
}
}
Is it okay to use the first approach to get the stored JSON?
For what cases the second approach should be used? It has far more code than the first one, maybe it has something to do with caching or/and speed/performance? What are the pros and cons of this approach?

The first approach is retrieving the document directly. This is the fastest way to do it.
With databases, though, often you want to retrieve documents based on some feature of the data. To do this you want the ability to create queries about the data. That's what the second approach is for.

Related

How to efficiently parse couchbase document to custom java/kotlin types on android?

I have some synced document from Sync gateway on local couchbase lite db. I need to parse this json document to my custom java type. But couchbase return me Map. I just want to know is there any way from which I could store Custom type in couchbase db while syncing from sync gateway.
Currently I am converting Map to Custom java type everytime I open the app. But this process takes some time and its affect my UI loading time.
I suggest you add a constructor (or a static initializer) to convert Map objects to your custom objects:
public class Pojo {
// ...
public Pojo() { }
public Pojo(Map<String, Object> json) {
String foo = (String) json.get("foo");
this.foo = (foo != null) ? foo : DEFAULT_FOO;
this.bar = Bar(json.get("bar"));
// ...
}
}
Unless your object are really just enormous, or there are hundreds of them, this should not take significant time.

create two tables using the same class in room database

I'm using Room as the database for the app. I`m fetching data from the server using Retrofit. the scenario is i have a class called Photo and annotated with Entity to be used by room, and im using this class to map the response of the API using retroft. i need to create two tables using the same class for example: latest_photos table and popular_photos table. How can i achieve this.
I don`t want to create a new class and make it extends from the other
I have an idea of using a single table through inserting a new column
that indicates weather the photo is popular or latest but i dont know
how to implement it efficientlly.
public void insertPhotos(final List photos) {
ioExecutor.execute(new Runnable() {
#Override
public void run() {
photoDao.bulkInsert(updateList(photos));
}
});
}
here im inserting list of photos (consists of 20 photo object). how can i add a new field to every photo object.
i`ve tried to use for loop but it takes noticeable time as i dont receive only 20 items but im paginating through the web server.
is there any way to add a new value to retrofit response and mapping
it to the Photo class
Ive solved the problem,now im dealing with only one table. i`ve inserted a new column that indicates weather the photo is popular or latest but the problem is the server is not returning any useful data to fill this column. so the only solution is to modify the json response before mapping to to my entity. so making retrofit call returning type to be ResponseBody to return json string itself and not to map it, so i can add a property to json response then i map it with the newly add property.
private void processData(Response<ResponseBody> response) {
if (response.isSuccessful()) {
try {
JSONObject jsonObject = new JSONObject(response.body().string());
JSONArray hits = jsonObject.getJSONArray("hits");
List<Photo> photos = new ArrayList<>();
for (int i = 0; i < hits.length(); i++) {
JSONObject photoJSONObject = hits.getJSONObject(i);
photoJSONObject.put("order", order); // add new property
String json = photoJSONObject.toString();
Gson gson = new Gson();
Photo photo = gson.fromJson(json, Photo.class);
photos.add(photo);
}

Find replicated docs cblite

How to find out whether a document from a cblite database has been replicated on android with the help of cblite api?
Came across this link but couldn't make any sense out of it.
Pouchdb. How to verify a doc is replicated
In cblite db each document has a sequence number, whenever each document gets replicated a sequence number is assigned to the document. Here's piece of code to get a better understanding,
//Get the latest sequence number of the document replicated
lastSeq = rep.getLastSequence();
Query query = database.createAllDocumentsQuery();
QueryEnumerator rowEnum = query.run();
for (Iterator<QueryRow> it = rowEnum; it.hasNext();) {
QueryRow row = it.next();
if(lastSequence!=null)
{
if(Long.parseLong(lastSequence)>=row.getSequenceNumber())
{
purgeDoc = row.getDocument();
purgeDoc.purge();
}
}
}

How to support one to many relationships with Azure Mobile Services Android

I just recently starting using Azure Mobile Services. I am in the process of setting up my database. However I am not sure how I am going to handle one to many/many to many relationships. Azure Mobile has not out of the box support for this so I am not sure what else to do. One approach would be to just store the foreign key id in a particular entity and then run a query on that table to get all items that match a particular id. I think that might be a bit too time consuming. Not sure. Any suggestions or insights on how this can be done.
Would I have to resort to creating some form of logic on the backend with JavaScript to create the actual relationships on the server side?
One way to support one to many relationships using the AMS for Android is to create an ArrayList and store the foreign keys/ids inside the the particular table. That ArrayList then contains the ids of the relevant entities that you want to retrieve so all you would have to do is retrieve the array and extract the ids. AWS does not support serialization and deserialization for ArrayList at the moment therefore would you have to write a custom serializer to achieve this. This can be done by using GSON. Here is an example.
public class CollectionSerializer<E> implements JsonSerializer<Collection<E>>,
JsonDeserializer<Collection<E>> {
public JsonElement serialize(Collection<E> collection, Type type,
JsonSerializationContext context) {
JsonArray result = new JsonArray();
for(E item : collection){
result.add(context.serialize(item));
}
return new JsonPrimitive(result.toString());
}
#SuppressWarnings("unchecked")
public Collection deserialize(JsonElement element, Type type,
JsonDeserializationContext context) throws JsonParseException {
JsonArray items = (JsonArray) new JsonParser().parse(element.getAsString());
ParameterizedType deserializationCollection = ((ParameterizedType) type);
Type collectionItemType = deserializationCollection.getActualTypeArguments()[0];
Collection list = null;
try {
list = (Collection)((Class<?>) deserializationCollection.getRawType()).newInstance();
for(JsonElement e : items){
list.add((E)context.deserialize(e, collectionItemType));
}
} catch (InstantiationException e) {
throw new JsonParseException(e);
} catch (IllegalAccessException e) {
throw new JsonParseException(e);
}
return list;
}
}
After this is complete you then add it to the MobileServiceClient instance you created.
mClient.registerSerializer(ArrayList.class,new CollectionSerializer<Object>());
An alternative to what Joel mentioned is that you can have "regular" relationships on the client side, and then denormalize them - not only the keys, but the whole values - prior to inserting them on the server. The post at http://blogs.msdn.com/b/carlosfigueira/archive/2013/08/29/complex-types-and-azure-mobile-services-android-version.aspx shows some ways where this can be done.

What is the fastest way to parse a JSON string into an SQLite table?

I'm writing an Android application which will occasionally need to download a json string of around 1MB and containing around 1000 elements, and parse each of these into an SQLite database, which I use to populate a ListActivity.
Even though the downloading and parsing isn't something that needs to be done on every interaction with the app (only on first run or when the user chooses to refresh the data), I'm still concerned that the parsing part is taking too long, at around two to three minutes - it seems like an eternity in phone app terms!
I'm currently using Gson to parse each json object into a custom object that I've defined, and then using an SQLiteOpenHelper to enter it into the database.
My question is - is there a faster way of implementing this? Would it be noticeably faster to interact with the json directly, without using Gson? Or am I doing something stupid in the code below that's slowing things down?
Here's the method I'm using in my AsyncTask to parse the json to SQLite:
protected Boolean doInBackground(Integer... bType) {
InputStream source = getJsonInputStream(bTypeString);
VegDataHandler db = new VegDataHandler(mainActivity, bTypeString);
Gson gson = new Gson();
Reader reader = new InputStreamReader(source);
JsonParser jParser = new JsonParser();
JsonArray jArray = jParser.parse(reader).getAsJsonArray();
aLength = jArray.size();
mCurrProgress = 1;
publishProgress(mCurrProgress, 0, aLength);
/* Each array element is of the form { company: {...} } */
int i = 0;
mCurrProgress = 2;
for (JsonElement obj : jArray) {
Company c = gson.fromJson(obj.getAsJsonObject().getAsJsonObject("company"), Company.class);
db.addCompany(c);
i++;
publishProgress(mCurrProgress, i);
}
}
This is the addCompany method from my VegDataHandler class, which extends SQLiteOpenHelper:
public void addCompany(Company c) {
SQLiteDatabase db = this.getWritableDatabase();
ContentValues values = new ContentValues();
values.put(KEY_ID, c.getCompanyId());
values.put(KEY_NAME, c.getCompanyName());
values.put(KEY_RYG, c.getCompanyRedYellowGreen());
values.put(KEY_COUNTRY, c.getCompanyCountry());
values.put(KEY_URL, c.getCompanyUrl());
values.put(KEY_NOTES, c.getCompanyNotes());
values.put(KEY_EMAIL, c.getCompanyEmail());
db.insertWithOnConflict(TABLE_COMPANY, null, values, SQLiteDatabase.CONFLICT_REPLACE);
db.close();
}
This is the class that holds each json element before adding to the SQLite (I've omitted the getters and setters for brevity).
public class Company {
public Company() {
}
#SerializedName("id")
public int companyId;
#SerializedName("company_name")
public String companyName;
#SerializedName("red_yellow_green")
public String companyRedYellowGreen;
#SerializedName("country")
public String companyCountry;
#SerializedName("url")
public String companyUrl;
#SerializedName("notes")
public String companyNotes;
#SerializedName("email")
public String companyEmail;
}
Thanks in advance for any replies.
First you need to determine the portion(s) of the process that are eating up the most time. From your comment above it sounds like the JSON parsing is the culprit.
If JSON parsing is the issue:
Research and consider a faster JSON parser. Perhaps something like json-smart.
If SQLite/DB bulk inserts are the issue:
See my answer here
General tips:
Recycle objects as much as possible (keep new to a minimum)
Always use transactions in DB bulk inserts at the very least
Don't open/close the database. Do this once at the start/finish of your processing
Use pre-compiled statements!

Categories

Resources