Using the google sheets api after completing quickstart tutorial - android

I'm pretty new to Android app development so please forgive my naivety.
I'm currently trying to develop an app that can pull data from a google spreadsheet and write data to it.
I've completed the quickstart tutorial so my code is the same as that right now. It all works correctly.
My issue is I need to be able to read from my own spreadsheet and I don't really understand the code used so I'm struggling to know where to start.
I've looked at this to try and implement the authorisation in fewer steps which I thought might make the code easier to understand - but again my lack of knowledge means I don't know how this fits into all the methods I currently have.
I've looked at the developer documentation and tried to replace the code from the quickstart which retrieves data from the app with this:
ValueRange result = service.spreadsheets().values().get(spreadsheetId, range).execute();
int numRows = result.getValues() != null ? result.getValues().size() : 0;
System.out.printf("%d rows retrieved.", numRows);
But again this is different to the code I already have so doesn't fit in as the getDataFromApi() method requires a return statement. I've tried just changing the spreadsheetId to that of my own spreadsheet and changing the range value to the cells I need,
/**
* Fetch a list of names and majors of students in a sample spreadsheet:
* https://docs.google.com/spreadsheets/d/1BxiMVs0XRA5nFMdKvBdBZjgmUUqptlbs74OgvE2upms/edit
* #return List of names and majors
* #throws IOException
*/
private List<String> getDataFromApi() throws IOException {
String spreadsheetId = "1-hL78Jm9-HijPx9UHthFxcXatkIhA2FR-AQ1lrCUbEg";
String range = "Go Mix 12 0506!B6:D";
List<String> results = new ArrayList<String>();
ValueRange response = this.mService.spreadsheets().values()
.get(spreadsheetId, range)
.execute();
List<List<Object>> values = response.getValues();
if (values != null) {
results.add("Name, Major");
for (List row : values) {
results.add(row.get(1) + ", " + row.get(3));
}
}
return results;
}
but I'm clearly going about it wrong because I get this error:
Invalid index 3, size is 3
I've also followed up to video 15 on this tutorial but it bypasses the need for any authorisation so didn't help.
Basically I've hit a brick wall and need someone to explain to me in simple terms how I can either work with the code from the quickstart tutorial to work with my own spreadsheet and fix that error! OR (more preferable to myself) explain how to do it myself from scratch. NB the spreadsheet cannot be public so I will need authorisation.
I hope that all makes sense!

You are asking to retrieve three columns of data (B through D), but then attempting to read a fourth column (rows.get(3)). In Java (and in most programming languages), lists and arrays are 0-based. So if you want the first item, you call list.get(0), and if you want the third you call list.get(2). This is evident based on the fact that the error message tells you your index of 3 is invalid since the list is size 3 -- you're attempting to read something beyond the end of the list.

Related

Multiple and() conditions in where clause for couchbase lite Android client

In my Android app we use couchbase lite database version 2.8.6
I run three database queries.
One item in where clause.
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE)))
In the result I see three items from database printed to a console. As expected. Format here ans below is id|timestamp|rating
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
I add and() condition to where() to get all items where type = 'type' AND rating < 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
)
Result is as expected as we search everything with rating < 1, third item is filtered out.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
Finally, I want to see records where type = 'type' AND rating < 1 AND timestamp <= 1
QueryBuilder.select(
SelectResult.property("id"),
SelectResult.property("timestamp"),
SelectResult.property("rating"))
.from(DataSource.database(database))
.where(Expression.property("type").equalTo(Expression.string(DOC_TYPE))
.and(Expression.property("rating").lessThan(Expression.intValue(1))
.and(Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
)
)
And now the result is really strange as I receive three items form the database. And the third one has timestamp much greater than 1 put into the query.
4e39f79c-9e11-4aba-9fb6-95d910f46cd9|0|-2147483648
e95646ee-ba3a-4978-b2a8-5383f31be2f1|0|-2147483648
e02d0eb3-6c9b-4942-b43c-a752eefc77a8|1630525956184|2147483647
Any ideas how to make it work with multiple and()? If I try to remove the second and() and keep the third one everything works as expected.
After deep investigations I found several problems in my code:
.and() should be called at the end of the "child" condition and not at the "parent" level.
For the conditions like this
val condition1 = Expression.property("type").equalTo(Expression.string(DOC_TYPE))
val condition2 = Expression.property("rating").lessThan(Expression.intValue(1))
val condition3 = Expression.property("timestamp")).lessThanOrEqualTo (Expression.longValue(1))
The correct way is
.where(condition1.and(
condition2.and(
condition3.and(
...
)
)
)
but NOT like I've tried
.where(condition1.and(condition2)
.and(condition3)
.and(...)
)
For the creation of the object I used a code that converts an object to Map<String, Any> before saving to couchbase. Everything seemed to be OK till I realized that Long was converted to Double.
The last point, I have much complicated queries and inside one of them I accidentally used .add() instead of .and(). No comments.
Hope this will help to somebody to save some time.
I would expect that the query would be as you did originally:
.where(condition1.and(condition2)
.and(condition3)
.and(...))
I think there is an additional parenthesis here that seems to be wrong:
.and(Expression.property("timestamp"))

Couchbase Lite - Sorting Map/Reduce by values

Advertissement: I'm using CouchbaseLite Android 1.4.0 and I'm not ready to switch to 2.0.
To get the context of my issue:
I have 2 doc types: PATIENT & VISIT
A patient is linked to a visit by a field visitId
A visit has a startDateTime and a endDateTime
A visit is considered as 'open' if the endDateTime is null or missing
A visit can be of different types through the field visitType
A visit can be inactive through the field inactive
I want to:
Get all patients (id + name) of all open and active visits of a certain type
The result is paginated using skip and limit
Get the result sorted by name
I managed to get all the correct patients and to paginate the result but the issue is with the sorting.
I can't make a 'post sorting' (getting the result in a random order and then use self-made method to sort them) because of the pagination.
So here is how it works actually without the sorting:
THE MAP/REDUCE
if (isVisit()) {
Object inactive = document.get(FIELDS.INACTIVE);
if(inactive == null)
inactive = false;
Document patientDoc = database.getExistingDocument(FIELDS.PATIENT_ID);
if(patientDoc != null && patientDoc.getProperties() != null) {
Object[] keys = {
document.get(CouchbaseVisitManager.FIELDS.STOP_DATE_TIME),
inactive,
document.get(CouchbaseVisitManager.FIELDS.VISIT_TYPE)
};
Object[] values = {
document.get(FIELDS.PATIENT_ID),
patientDoc.getProperties().get(FIELDS.FAMILY_NAME),
patientDoc.getProperties().get(FIELDS.FIRST_NAME)
}
emitter.emit(keys, values);
}
}
THE QUERY
Query query = getQuery(Views.PATIENTS_CURRENTLY_IN_VISIT); //Helper method to create a query
query.setKeys(new ArrayList<Object>(){{
add(new ArrayList<Object>(){{
add(null);
add(false);
add(visitType);
}});
}});
query.setSkip(skip);
query.setLimit(limit);
And this is working well to get my patients but not for sorting them.
I tried to add patient names inside the view like this:
Object[] keys = {
patientDoc.getProperties().get(FIELDS.FAMILY_NAME),
patientDoc.getProperties().get(FIELDS.FIRST_NAME),
document.get(FIELDS.STOP_DATE_TIME),
inactive,
document.get(FIELDS.VISIT_TYPE)
};
And update my query.keys like this:
query.setStartKey(new ArrayList<Object>(){{
add(null);
add(null);
add(null);
add(false);
add(visitType);
}});
query.setEndKey(new ArrayList<Object>(){{
add(new HashMap<>());
add(new HashMap<>());
add(null);
add(false);
add(visitType);
}});
But this returns no patients (result.size = 0)
So... I don't know how to achieve my goal.
I tought of a way to sort by values but it doesn't seem to exist yet (should wait for 2.0 I think). But is their any workaround to achieve this kind of behavior?
Thank's for reading.
View results are always sorted by key. So you should add the patient name to the key and then you'll get your sorting.
Be careful to put the name into the correct place of the keys array since the sorting is lexicographical, that is if the name is going to be the last component then you'll get all open inactive sorted by name, then all open active sorted by name e.t.c.
In case you need to put your name key in front of the other keys but still be able to filter your results, then you will need to properly construct the start key and the end key so that the full range of every possible patient names would be accepted while the later keys would be filtered.
You will have to provide some values which will definitely be less than or greater than any possible patient name.
Following the key collation defined for Couchbase views, a null will be always less than any string, and an empty map {} can be used to match past the last string. You are basically doing it right in your last sample.
Don't forget to switch the start and end keys logic if you would like to query the view in reverse mode
Another thing to take care of is always incrementing the version of the view after changing its logic or key set, otherwise you will continue getting old results. Incrementing the version will force a refresh of the view, executing the updated logic in the view function over all your data.

How to write and update data to google spreadsheet android (api v4)

I have followed the Android Quickstart provided by google Google Sheets API Android Quickstart and was able to retrieve data from the google spreadsheet but I am not able to understand how to write and update single or multiple data.
I read this code from StackOverflow, I think It's good but I can't understand how to set (valueRange) object here
this.mService.spreadsheets().values().update(spreadsheetId, range, valueRange)
.setValueInputOption("RAW")
.execute();
In case you still need the answer, or for anyone else who does:
I faced the same issue too, and from the docs, I was able to work this out.
Here's a method in which i write the data to the sheet
private void writeDataToApi() throws IOException {
String spreadsheetId = "the_spreadsheet_id_like_the_google_example";
String range = "YourSheetName!A1:B1"; //Read the docs on how these ranges work.
//Currently, this is the range of a single row which would return
//as [[objA, objB]] if major dimension is set as ROW.(default).
// would be [[objA],[objB]] if its set to COLUMN. Read the doc for more info.
//for the values that you want to input, create a list of object lists
List<List<Object>> values = new ArrayList<>();
//Where each value represents the list of objects that is to be written to a range
//I simply want to edit a single row, so I use a single list of objects
List<Object> data1 = new ArrayList<>();
data1.add("objA");
data1.add("objB");
//There are obviously more dynamic ways to do these, but you get the picture
values.add(data1);
//Create the valuerange object and set its fields
ValueRange valueRange = new ValueRange();
valueRange.setMajorDimension("ROWS");
valueRange.setRange(range);
valueRange.setValues(values);
//then gloriously execute this copy-pasted code ;)
this.mService.spreadsheets().values()
.update(spreadsheetId, range, valueRange)
.setValueInputOption("RAW")
.execute();
//Try calling this method before executing the readDataFromApi method,
//and you'll see the immediate change
}
I hope this helped.
And for more info, pls see the docs
EDIT: Also remember to change scope from SheetsScopes.SPREADSHEETS_READONLY to SheetsScopes.SPREADSHEETS

Youtube-api v3: is it possible to get videos on a certain order?

i'm trying to get certain order from youtube videos on my Android application. I want to search, for example:
Fight 1
Fight 2
Fight 3
Fight 4
This is my search list:
YouTube.Search.List search = mYouTubeDataApi.search().list("id,snippet");
search.setKey(ApiKey.YOUTUBE_API_KEY);
search.setQ(mTitle + " " + mSearchQuery);
search.setType("video");
search.setFields("items(id/kind,id/videoId,snippet/title,snippet/thumbnails/default/url)");
search.setMaxResults(YOUTUBE_PLAYLIST_MAX_RESULTS);
searchResponse = search.execute();
So far, i've tried adding to my Search List:
search.setOrder("title");
and also i tried to sort manually the items this way
List<Video> items = videoListResponse.getItems();
Collections.sort(items, new Comparator<Video>() {
#Override
public int compare(Video video, Video t1) {
return video.getSnippet().getTitle().compareToIgnoreCase(t1.getSnippet().getTitle());
}
});
return new Pair(searchResponse.getNextPageToken(), items);
but i still don't get the results as i expect, and my sort is not good (i.e.: fight 1, fight 10, fight 11, fight 2, etc...)
Thanks in advance!
You can use Search: list using the HTTP request:
GET https://www.googleapis.com/youtube/v3/search
with the optional parameter order added to the query.
As discussed in the documentation,
The order parameter specifies the method that will be used to order resources in the API response.
Acceptable values are:
date – sorted in reverse chronological order based on the date they were created.
rating – sorted from highest to lowest rating.
relevance – sorted based on their relevance to the search query. This is the default value for this parameter.
title – sorted alphabetically by title.
videoCount – Channels are sorted in descending order of their number of uploaded videos.
viewCount – sorted from highest to lowest number of views. For live broadcasts, videos are sorted by number of concurrent viewers while the broadcasts are ongoing.

Possible to query against the count of an included key?

I have an application where I need to return the first user found that meets certain criteria, some of that criteria is having a certain number of objects stored.
For example, let's say I want to return the first store I can find that has at-least 3 employees with atleast two children. I know, what an odd-ball example. So I would have a query something like this:
PFUser.query()?
.whereKey("objectId", notEqualTo: PFUser.currentUser()?.objectId!)
.includeKey("stores.employees.children")
// .whereCountForkey("stores.employees", greaterThan: 2)
// .whereCountForKey("stores.employees.children", greaterThan: 1)
.getFirstObject();
Notice the commented out lines, I'm trying to find a way to do soemthing like this in a single query. I'm using parse, which I believe uses MongoDB on the back end, but I don't believe you can execute custom database queries..?
This is a mobile application for both iOS and Android, although the code shown is in SWIFT I have two variations of the project. Examples in either swift, obj-C, Java, or C# will be fine.
Also more than happy with Cloud-code solutions.
There is an example in the documentation
var Team = Parse.Object.extend("Team");
var teamQuery = new Parse.Query(Team);
teamQuery.greaterThan("winPct", 0.5);
var userQuery = new Parse.Query(Parse.User);
userQuery.matchesKeyInQuery("hometown", "city", teamQuery);
userQuery.find({
success: function(results) {
// results has the list of users with a hometown team with a winning record
}
});

Categories

Resources