Google表格API:如何按值查找行并更新其内容

时间:2018-03-07 21:10:05

标签: android google-sheets google-api google-sheets-api

我正在开发一个使用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 等概念,我觉得我应该将这些功能用于我想要实现的目标,但我无法将它们放在一起,我找不到任何示例。

有人可以告诉我或帮助我了解如何使用这些Shee​​ts V4功能吗?

谢谢。

3 个答案:

答案 0 :(得分:17)

我有完全相同的问题,似乎到目前为止(2018年3月)Sheets v4 API不允许按值搜索,返回单元格地址。我在StackOverflow上找到的解决方案是使用公式。每次要按值查找地址时,都可以在任意工作表中创建公式,然后删除公式。如果您不想每次都删除公式,则许多人更喜欢在更安全的地方创建,例如隐藏的工作表。

  1. 创建隐藏的工作表LOOKUP_SHEET(spreadsheetId是您的电子表格ID):
  2. POST https://sheets.googleapis.com/v4/spreadsheets/spreadsheetId:batchUpdate

    {
     "requests": [
      {
       "addSheet": {
        "properties": {
         "hidden": true,
         "title": "LOOKUP_SHEET"
        }
       }
      }
     ]
    }
    
    1. 在隐藏工作表的A1单元格中创建一个公式,在MySheet1工作表中搜索“搜索值”,然后返回该行:
    2. 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)"
        ]
       ]
      }
      

      响应将如下所示:

      {
       "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"
            }
          }
        }
      ]
    }});
  }
}

我们需要小心竞争条件,因为我们最终可能会得到重复的行,如果这有帮助,请告诉我:)