Filter array field in couchbase - android

I m working on couchbase lite android.
I have series of documents, every document contains a field which it's value is array of string.
now I want to filter value of this field.
{
type : "customer",
name: "customerX",
states: [ "IL" , "IO" , "NY" , "CA" ]
},
{
type : "customer",
name: "customerY",
states: [ "WY" , "CA", "WA" ]
},
{
type : "customer",
name: "customerZ",
states: [ "NY" ]
}
I want to get customer documents which have "CA" in their states field.
I m using CBL Android.
emit(states , null);
then how could I make my Start and End Key option.
startkey("CA")
Or
startKey(["CA"])
customerX customerY
how can i get only customerX and customerY by "CA" in their states field ?!

If you are just wanting to filter on one state then your best solution would be to make a view like this:
function (doc, meta) {
if(doc.type && doc.type == "customer") {
if(doc.states) {
for (index = 0, len = doc.states.length; index < len; ++index) {
emit(doc.states[index],null);
}
}
}
}
This view will emit a view row for each state in the arrays of each of your documents of type 'customer'. This means that you can then select an individual state with a startkey of "CA" and an endkey of "CA", remember to set the inclusive_true flag to true so that endkeys that match are included:
startkey="CA"&endkey="CA"&inclusive_end=true
Hope that helps!

Related

How to create JSON object in flutter?

I'm working on one application in which I want to fill the registration form and pass this data to API.I tried almost all solutions but not solved this issue.
I'm getting this type of data after filling the form
[
{Date of Birth of the Baby: 08/01/1997},
{Gender of the baby: male},
{Time of Birth of the Baby: 12.00 pm},
{Father's Name: Nnn},
{Mother's Name: Hbhh},
{Any Extra Details?: Bnn}
]
and I want this type of data
{
"Date of Birth of the Baby": "08/01/1997",
"Gender of the baby": "male",
"Time of Birth of the Baby": "12.00 pm",
"Father's Name": "Nnn",
"Mother's Name": "Hbhh",
"Any Extra Details?": "Bnn"
}
var fieldsData = [];
final myControllers = [];
mydynamicData() {
for (var i = 0; i <= widget.fieldData.length; i++) {
fieldsData.add({
widget.fieldData[i]['question'],
myControllers[i].text != null || myControllers[i].text != ""
? myControllers[i].text
: ""
});
}
print("fieldsData:${fieldsData}");
}
This is my method i know this issue occurred due to for loop but without for loop I'm not getting all fields data. so please help.
Import:
import 'dart:convert';
then you can use:
json.encode(fieldsData);
As you have a list of objects, it may be necessary to make a for in the list calling json.encode for each item, then encoding the result.

Executing a for loop after one is finished in flutter

Server response returning three JSON arrays and all the objects are stored in database one by one and optionsGroupList, attributes, assignedattributes.
In the Project I have three tables are named as a group, attribute, and assignedattribute. firstly I have to insert all the elements of optionsGroupList in group table and I'm able to do so, In the second array I'm getting groupid, attributeid, attributename but in the second table I have 4 columns which have
groupid, attributeid,attributename,groupname, but for the groupname I have to get the record of a particular group by group id from group table but my second loop executes first so I'm not able to get the group record because of the loop still inserting records that time my second loop has started before completing first, my second table depends on the first and my third table depends on the second so I need to insert record after one is finished. Sometimes it works correctly
{
"result": 1,
"data": "optionsList",
"merchantid": "MER-07156",
"optionsGroupList": [{
"grouprowid": "3012",
"groupname": "Color",
"isrequired": "0"
}],
"attributes": [{
"attributerowid": "20794",
"grouprowid": "3012",
"attributename": "Red",
"weight": "0"
}],
"assignedattributes": [{
"attributegrouprowid": "154577",
"productrowid": "342702",
"attributerowid": "20794",
"subsku": "",
"quantity": "0",
"pricechange": "4"
},
{
"attributegrouprowid": "154590",
"productrowid": "354723467",
"attributerowid": "20794",
"subsku": "0",
"quantity": "0",
"pricechange": "0"
}
]
}
My Second loop debug statement printing before first.
optionListService().then((onValue) async {
if (onValue.result == 1) {
//Loop 1
for(int i=0;i<onValue.optionsGroupList.length;i++){
_insertOption(onValue.optionsGroupList[i]);
}
//Loop 2
for(int j=0;j<onValue.attributes.length;j++){
debugPrint('Attribute Name:--${ onValue.attributes[j].attributename}');// this is printed first before first loop excuted
List groupIdList=new List<Map<String,dynamic>>();
groupIdList= await dbHelper.queryReadOption(onValue.attributes[j].grouprowid); // here i'm finding group name from group table but i think is executing first.
if(groupIdList.length>0){
_insertOptionAttribute(onValue.attributes[j],groupIdList[0][DatabaseHelper.columnGroupName],groupIdList[0][DatabaseHelper.columnIsRequired]);
}
}
//Loop 3
for(int i=0;i<onValue.assignedattributes.length;i++){
String attr=onValue.assignedattributes[i].attributerowid;
arrtIdList=new List<Map<String,dynamic>>();
arrtIdList= await dbHelper.queryReadAttribute(attr);
if(arrtIdList.length>0){
_insertProductWithAttribute(
onValue.assignedattributes[i],
arrtIdList[0][DatabaseHelper.columnGroupId],
arrtIdList[0][DatabaseHelper.columnGroupName],
arrtIdList[0][DatabaseHelper.columnAttributeName],
arrtIdList[0][DatabaseHelper.columnIsRequired],
arrtIdList[0][DatabaseHelper.columnWeight]
);
}
}}});}
just add second loop in chained "then" block and in first block return "onValue" varibale. like so:
optionListService().then((onValue) async {
if (onValue.result == 1) {
//Loop 1
for(int i=0;i<onValue.optionsGroupList.length;i++){
_insertOption(onValue.optionsGroupList[i]);
}
}
return onValue;
}).then((onValue) {
if (onValue.result == 1) {
//Loop 2
for(int j=0;j<onValue.attributes.length;j++){
// some code
}
}
});

Google Sheets API: How to find a row by value and update it's content

I am working on an Android application that uses a Google Spreadsheet as a database.
The application should GET, APPEND and UPDATE values in a spreadsheet, using the Sheets API v4. The first two functions are working fine but I have difficulties updating a specific row. I need to find a row that has a specific value in it's first column ("Batch ID") and update all the cells in this row.
This is how my spreadsheet looks like.
Right now I am getting the row to be modified like this:
ValueRange response = this.mySheetsService.spreadsheets().
values().get(spreadsheetId, range).execute();
List<List<Object>> values = response.getValues();
String rangeToUpdate;
Log.i(TAG, "all values in range: " + values.toString());
int i = 0;
if (values != null) {
for (List row : values) {
i += 1;
if (row.get(0).equals(selectedBatchID)) {
Log.i(TAG, "IT'S A MATCH! i= " + i);
rangeToUpdate = "A" + (i + 1) + ":E" + (i + 1); //row to be updated
}
}
}
/*once I have the row that needs to be updated, I construct my new ValueRange requestbody and
*execute a values().update(spreadsheetId, rangeToUpdate , requestbody) request.
*/
This is actually working fine but I think it's an ugly solution and I am sure there is a better one out there.
I have read the Sheets API documentation and I got familiar with notions such as batchUpdateByDataFilter, DataFilterValueRange or DeveloperMetadata and I sense that I should use these features for what I'm trying to achieve but I couldn't put them together and I couldn't find any examples.
Can someone show me or help me understand how to use these Sheets V4 features?
Thank you.
I have exactly the same issue, and it seems that so far (March 2018) Sheets v4 API does not allow to search by value, returning cell address. The solution I found somewhere here on StackOverflow is to use a formula. The formula can be created in an arbitrary sheet each time you want to find the address by value, then you erase the formula. If you do not want to delete the formula every time, you many prefer to create in a safer place, like a hidden worksheet.
Create hidden worksheet LOOKUP_SHEET (spreadsheetId is your spreadsheet ID):
POST https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId:batchUpdate
{
"requests": [
{
"addSheet": {
"properties": {
"hidden": true,
"title": "LOOKUP_SHEET"
}
}
}
]
}
Create a formula in the A1 cell of the hidden worksheet that searches for "Search value" in MySheet1 sheet, and get back the row:
PUT https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId/values/LOOKUP_SHEET!A1?includeValuesInResponse=true&responseValueRenderOption=UNFORMATTED_VALUE&valueInputOption=USER_ENTERED&fields=updatedData
{
"range": "LOOKUP_SHEET!A1",
"values": [
 [
  "=MATCH("Search value", MySheet1!A:A, 0)"
 ]
]
}
The response will look like this:
{
"updatedData": {
 "range": "LOOKUP_SHEET!A1",
 "majorDimension": "ROWS",
 "values": [
  [
   3
  ]
 ]
}
}
By default, major dimension is ROWS. MATCH() returns relative row within column A, if no row IDs are provided then this position is effectively absolute. Or, you may want to use a more reliable call like =ROW(INDIRECT(ADDRESS(MATCH("Search value",A:A,0),1))). If the sheet has spaces in it, enclose it in single quotes. If you are searching for number, make sure you do not enclose it in quotes.
In the spreadsheets API we have the concept of developer metadata, that allow us to store information not visible to the end user that we can later on retrieve and use.
In this case the best approach is to assign the Batch ID as a metadata for a particular row. I will add the code based on the Javascript SDK.
const response = await sheets.spreadsheets.developerMetadata.search({
auth: jwtClient,
spreadsheetId,
requestBody: {
dataFilters: [
{
developerMetadataLookup: {
locationType: 'ROW',
metadataKey: 'batchId',
metadataValue: '$BATCH_ID'
}
}
]
}
});
if (response.matchedDeveloperMetadata) {
// There is a row with that id already present.
const { endIndex } = response.matchedDeveloperMetadata[0].developerMetadata.location.dimensionRange;
// Use endIndex to create the range to update the values range: `SheetName!A${endIndex}`,
await sheets.spreadsheets.values.update(
{
auth: jwtClient,
spreadsheetId,
range: `SheetName!A${endIndex}`,
valueInputOption: 'USER_ENTERED',
requestBody: {
majorDimension: 'ROWS',
values: [[]]
},
},
{}
);
} else {
// Append the value and create the metadata.
const appendResponse = await sheets.spreadsheets.values.append(
{
auth: jwtClient,
spreadsheetId,
range: 'SheetName!A1',
valueInputOption: 'USER_ENTERED',
requestBody: {
majorDimension: 'ROWS',
values: [[]]
},
},
{}
);
if (appendResponse.data.updates?.updatedRange) {
const updatedRange = appendResponse.data.updates?.updatedRange;
const [, range] = updatedRange.split('!');
const indexes = convertSheetNotation(range);
await sheets.spreadsheets.batchUpdate({ auth: jwtClient, spreadsheetId, requestBody: {
requests: [
{
createDeveloperMetadata: {
developerMetadata: {
location: {
dimensionRange: {
sheetId: 0,
startIndex: indexes[0],
endIndex: indexes[0] + 1,
dimension: "ROWS"
}
},
metadataKey: 'batchId',
metadataValue: '$BATCH_ID',
visibility: "DOCUMENT"
}
}
}
]
}});
}
}
We need to be careful of race conditions as we may end up with duplicated rows, let me know if that helps :)
I had the same requirement.
First:
Create a function that gets the index of targeted object from the sheet, like:
private int getRowIndex(TheObject obj, ValueRange response) {
List<List<Object>> values = response.getValues();
int rowIndex = -1;
int i = 0;
if (values != null) {
for (List row : values) {
i += 1;
if (row.get(1).equals(obj.getBatchId())) {
System.out.println("There is a match! i= " + i);
rowIndex = i;
}
}
}
return rowIndex;
}
Second:
Create the update method by passing the targeted object having your desired value "batch id" and others new values for the rest of fields.
public void updateObject(Object obj) throws IOException, GeneralSecurityException {
sheetsService = getSheetsService();
ValueRange response = sheetsService.spreadsheets().
values().get(SPREADSHEET_ID, "Sheet1").execute();
int rowIndex = this.getRowIndex(obj, response);
if (rowIndex != -1) {
List<ValueRange> oList = new ArrayList<>();
oList.add(new ValueRange().setRange("B" + rowIndex).setValues(Arrays.asList(
Arrays.<Object>asList(obj.getSomeProprty()))));
oList.add(new ValueRange().setRange("C" + rowIndex).setValues(Arrays.asList(
Arrays.<Object>asList(obj.getOtherProprty()))));
//... same for others properties of obj
BatchUpdateValuesRequest body = new BatchUpdateValuesRequest().setValueInputOption("USER_ENTERED").setData(oList);
BatchUpdateValuesResponse batchResponse;
batchResponse sheetsService.spreadsheets().values().batchUpdate(SPREADSHEET_ID, body).execute();
} else {
System.out.println("the obj dont exist in the sheet!");
}
}
Finally:
In your app you have to pass the tageted object to the update method:
TheObject obj = new Object();
obj.setBatchId = "some value";
Fill the obj with others values if you want.
Then call the method:
objectChanger.updateObject(obj);
All you need to do is to create a new array of strings from an array of arrays - so you can run the indexOf() method on this new array.
Since we know the method values.get returns array of the arrays such as
[
[""],
[""],
...
]
my approach was to a bit flattened this structure.
const data = await googleSheetsInstance.spreadsheets.values.get({
//here u have to insert auth, spreadsheetId and range
});
//here you will get that array of arrays
const allData: any[] = data.data.values;
//Now you have to find an index in the subarray of Primary Key (such as
//email or anything like that
const flattenedData = allData.map((someArray: any[]) => {
return someArray[2]; //My primary key is on the index 2 in the email
Array
});
So what you will get is a normal array of strings with primary keys so now you can easily call the indexOf() on the flattened array.
const index:number = flattenedData.indexOf("someuniquestring);
console.log(index);
And the index value will tell you the row. Do not forget spreadsheets start from 1 and indexes in Javascript start from 0.

How to array listing index from Firebase on Android

0 --> David
1 --> Alice
2 --> Jayden
3 --> Nicole
4 --> David
this sequence shows 0 and 4 David's records. I want to find David's records and find index values.
find --> David
Situated shows list --> data to recyclerview listing
i want to do
My Firebase ;
"Node" : {
"-L1pFRQg8anT4_-4V60B" : {
"name" :"David"
"note" : " firs note"
}, "-L1pFRQg8anT4_-4V2342" : {
"name" :"Alice"
"note" :"note values"
}, "-L1pFRQg8anT4_-65656" : {
"name" :"Jayden"
"note" :"note values"
}, "-L1pFRQg8anT4_-sajkfhsaj" : {
"name" :"Nicole"
"note" :"note values"
}, "-L1pFRQg8anT4_-jwquh24" : {
"name" :"David"
"note" :"second note"
},
I know how to read and print data with Firebase. I know how to use FirebaseRecyclerview. But I have to find out in what order David is in the order of number. So if I called "David", it would be easy to show Davids in Recyclerview. I can do that. It is difficult to print the rank value of "David" among other data. etc 0-4
Query query = FirebaseDatabase.getInstance ()
.getreferen by ()
.child ( "node")
.orderbychild ( "name");
When I sort by name, I want to get "David" in position number and print it as "note" data and "position number".
I want to do index values

Android Cloudant sync query

as docs say( https://github.com/cloudant/sync-android/blob/master/doc/query.md) im trying to do a query inside a list
look:
query.put("codigo", 4);
result = q.find(query);
for (DocumentRevision revision : result) {
Log.d("QueryTest", "Test1 :" + revision.getBody().toString());
}
return:
{ "codigo":4, "companies":[
{
"id":"b9f19d88-13c0-40e3-89de-63dc787afb4c",
"name":"Filial 0 1488949817178"
},
{
"id":"f17fb098-316e-4d33-a0f7-f5719bf9d62e",
"name":"Filial 1 1488949817178"
} ], "employees":[
{
"codigo":2891,
"id":"cc54fa37-0b64-4108-869a-1303c6176ce5",
"name":"Employee 0 79ed4"
},
{
"codigo":4642,
"id":"19b76bbc-82c7-4295-a385-82ac2d892458",
"name":"Employee 1 e1102"
} ], "id":"ef2d0ebf-50b9-4cd0-9aaf-5389bccaaa56", "nome":"Random 4" }
so its ok
but this query doesnt work:
query.put("employees.codigo", 2891);
first return:
QuerySqlTranslator: No single index contains all of
[{employees.codigo={$eq=2891}}]; add index for these fields to query
efficiently
after created the index:
Index i = q.createJsonIndex(Arrays.<FieldSort>asList(new FieldSort("employees.codigo")), null);
return
QueryExecutor: Projection fields array is empty, disabling project for
this query
so i created the arraylist of fields to filter
List<String> fields = Arrays.asList("codigo");
result = q.find(query, 0 , 0 , fields, null);
nothing returned
adding more one field to filter:
query.put("codigo",4)
query.put("employees.codigo", 2891);
returned: Complain about index
Created another index:
i = q.createJsonIndex(Arrays.<FieldSort>asList(new FieldSort("employees.codigo"), new FieldSort("codigo")), null);
returned: Nothing
whats is wrong?
How can i get document by child and how can i get ONLY the children?
thanks
I think this is unsupported, see the doc on unsupported features, specifically the highlighted entry:
Arrays
Dotted notation to index or query sub-documents in arrays.
Querying for exact array match, { field: [ 1, 3, 7 ] }.
Querying to match a specific array element using dotted notation, { field.0: 1 }.
Querying using $all.
Querying using $elemMatch.

Categories

Resources