我正在开发一个使用Google电子表格作为数据库的Android应用程序。 应用程序应使用Sheets API v4在电子表格中获取GET,APPEND和UPDATE值。前两个函数工作正常但我更新特定行时遇到困难。我需要在它的第一列(“批次ID”)中找到一个具有特定值的行,并更新该行中的所有单元格。
这就是我的电子表格的样子。
现在我正在修改这样的行:
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.
*/
这实际上工作正常,但我认为这是一个丑陋的解决方案,我相信那里有一个更好的解决方案。
我已阅读Sheets API文档,并熟悉 batchUpdateByDataFilter , DataFilterValueRange 或 DeveloperMetadata 等概念,我觉得我应该将这些功能用于我想要实现的目标,但我无法将它们放在一起,我找不到任何示例。
有人可以告诉我或帮助我了解如何使用这些Sheets V4功能吗?
谢谢。
答案 0 :(得分:17)
我有完全相同的问题,似乎到目前为止(2018年3月)Sheets v4 API不允许按值搜索,返回单元格地址。我在StackOverflow上找到的解决方案是使用公式。每次要按值查找地址时,都可以在任意工作表中创建公式,然后删除公式。如果您不想每次都删除公式,则许多人更喜欢在更安全的地方创建,例如隐藏的工作表。
POST https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId:batchUpdate
{
"requests": [
{
"addSheet": {
"properties": {
"hidden": true,
"title": "LOOKUP_SHEET"
}
}
}
]
}
{
"range": "LOOKUP_SHEET!A1",
"values": [
[
"=MATCH("Search value", MySheet1!A:A, 0)"
]
]
}
响应将如下所示:
{
"updatedData": {
"range": "LOOKUP_SHEET!A1",
"majorDimension": "ROWS",
"values": [
[
3
]
]
}
}
默认情况下,主要维度为ROWS。 MATCH()返回A列中的相对行,如果没有提供行ID,则此位置实际上是绝对的。或者,您可能希望使用更可靠的调用,例如= ROW(间接(地址(匹配(“搜索值”,A:A,0),1)))。如果工作表中有空格,请将其用单引号括起来。如果您要搜索号码,请确保不要将其括在引号中。
答案 1 :(得分:2)
我有相同的要求。
第一: 创建一个从工作表获取目标对象索引的函数,例如:
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;
}
第二: 通过传递具有所需值“批次ID”和其余字段其他新值的目标对象,创建更新方法。
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!");
}
}
最后: 在您的应用中,您必须将tageted对象传递给update方法:
TheObject obj = new Object();
obj.setBatchId = "some value";
如果需要,用其他值填充obj。
然后调用方法:
objectChanger.updateObject(obj);
答案 2 :(得分:0)
在电子表格 API 中,我们有开发人员元数据的概念,它允许我们存储最终用户不可见的信息,以便我们以后检索和使用。 在这种情况下,最好的方法是将批次 ID 分配为特定行的元数据。我将添加基于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"
}
}
}
]
}});
}
}
我们需要小心竞争条件,因为我们最终可能会得到重复的行,如果这有帮助,请告诉我:)