Google App Script 过滤后如何更新单元格

How to update cell in Google App Script after it has been filtered

我有以下脚本,它们从示例电子表格的“交易”选项卡获取数据,然后 运行 sumActual 中的逻辑,例如在 sumActual 选项卡中分组和设置值。这一切都很好。

然而,在函数 sumActual 的末尾,我注意到 // 设置已处理的交易。我想在“T”列中设置今天的日期以标记已处理的行。但是我需要使用 sumActuals 中的“const filterProcessedTransactions”,因为它会过滤掉那些已经处理过的行。我不太确定该怎么做。

任何帮助都会很棒。

样本Sheet

https://docs.google.com/spreadsheets/d/17SId7mIzO3hVOC36Nq40O0bjPS5YfGOX4wsMU1NlbCU/edit?usp=sharing

function sumActual () {
  const _ = LodashGS.load()
  eval(UrlFetchApp.fetch('https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js').getContentText())

  const transactions = getTransactions()
  // console.log({ transactions })

  const filterProcessedTransactions = _.filter(transactions, (o) => {
    return !moment(o.Processed).isValid()
  })
  // console.log({ filterProcessedTransactions })

  // Group By Category
  const grouped = _.groupBy(filterProcessedTransactions, (o) => {
    return [o.Category, o.Year, o.Month]
  })
  // console.log({ grouped })

  // sum amount
  const result = _.map(grouped, function (value, key) {

    const d = value[0].Month + '/1/' + value[0].Year
    const startOf = moment(d).format('MM/DD/YYYY')
    const valid = moment(startOf).isValid()
    // console.log({ d, startOf, valid })

    return {
      category: value[0].Category,
      month: value[0].Month,
      year: value[0].Year,
      amount: _.reduce(value, function (total, o) {
        return Math.abs(total + o.Amount)
      }, 0),
      startofMonth: startOf
    }
  })
  // console.log({ result })

  // lookup, merge, sum and update sumActuals
  const obj = result.reduce((o, { category, amount, startofMonth }) => (o[startofMonth + category] = amount, o), {})
  console.log({ obj })

  const sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName('sumActual')
  const [[, ...header], , ...values] = sheet.getDataRange().getValues()
  const res = values.map(([h, ...v]) => v.map((f, j) => {
    const key = Utilities.formatDate(header[j], Session.getScriptTimeZone(), 'MM/dd/yyyy') + h
    return obj[key] ? obj[key] + f : f
  }))
  console.log({ res })

  sheet.getRange(3, 2, res.length, res[0].length).setValues(res)

  // set transactions processed
  
}

function getTransactions () {
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  const transactionSheet = ss.getSheetByName('Transactions')
  const lastRow = transactionSheet.getLastRow()
  const lastColumn = transactionSheet.getLastColumn()
  const values = transactionSheet.getRange(1, 1, lastRow, lastColumn).getValues()
  const [headers, ...originalData] = values.map(([, b,, d, e,,,,,,,,,,, p, q, r, s, t]) => [b, d, e, p, q, r, s, t])
  const res = originalData.map(r => headers.reduce((o, h, j) => Object.assign(o, { [h]: r[j] }), {}))
  return res
}

示例解决方案:

如果您愿意将脚本处理的所有 t运行 操作 运行 视为已处理,最简单的方法是直接设置列值:

这个函数应该这样做:

function setTransactionsProcessed () {
  const ss = SpreadsheetApp.getActiveSpreadsheet()
  const transactionSheet = ss.getSheetByName('Transactions')
  const lastRow = transactionSheet.getLastRow()
  const lastColumn = transactionSheet.getLastColumn()
  const range = transactionSheet.getRange(2,lastColumn,lastRow-1)
  const processedArr = range.getValues();
  for (i = 0; i < processedArr.length; i++) {
    if (processedArr[i] == '') {
      const d = new(Date);
      processedArr[i][0] = d;
    }
  }
  range.setValues(processedArr);
}

这将在过滤掉已处理的 t运行sactions:

后调用

  const transactions = getTransactions()
   console.log({ transactions })

  const filterProcessedTransactions = _.filter(transactions, (o) => {
    return !moment(o.Processed).isValid()
  })
   console.log({ filterProcessedTransactions })

  setTransactionsProcessed();

  // Group By Category
  const grouped = _.groupBy(filterProcessedTransactions, (o) => {
    return [o.Category, o.Year, o.Month]
  })
  // console.log({ grouped })

示例输出:

保留原始索引

您可以这样做并通过添加一个名为 idx 的额外列来保留原始索引

function getTransactions () {
  const ss = SpreadsheetApp.getActive()
  const transactionSheet = ss.getSheetByName('Sheet0')
  const lastRow = transactionSheet.getLastRow()
  const lastColumn = transactionSheet.getLastColumn()
  const values = transactionSheet.getRange(1, 1, lastRow, lastColumn).getValues()
  const [headers, ...originalData] = values.map(([, b,, d, e,,,,,,,,,,, p, q, r, s, t]) => [b, d, e, p, q, r, s, t])
  const res = originalData.map((r,i) => headers.reduce((o, h, j) => Object.assign(o, { [h]: r[j],idx:i }), {}))
  return res;
}