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;
}
我有以下脚本,它们从示例电子表格的“交易”选项卡获取数据,然后 运行 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;
}