✨ Add lookup operation to GoogleSheets-Node
This commit is contained in:
@@ -18,6 +18,10 @@ export interface ISheetUpdateData {
|
|||||||
values: string[][];
|
values: string[][];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ILookupValues {
|
||||||
|
lookupColumn: string;
|
||||||
|
lookupValue: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class GoogleSheet {
|
export class GoogleSheet {
|
||||||
id: string;
|
id: string;
|
||||||
@@ -146,7 +150,7 @@ export class GoogleSheet {
|
|||||||
/**
|
/**
|
||||||
* Returns the given sheet data in a strucutred way
|
* Returns the given sheet data in a strucutred way
|
||||||
*/
|
*/
|
||||||
structureData(inputData: string[][], startRow: number, keys: string[]): IDataObject[] {
|
structureData(inputData: string[][], startRow: number, keys: string[], addEmpty?: boolean): IDataObject[] {
|
||||||
const returnData = [];
|
const returnData = [];
|
||||||
|
|
||||||
let tempEntry: IDataObject, rowIndex: number, columnIndex: number, key: string;
|
let tempEntry: IDataObject, rowIndex: number, columnIndex: number, key: string;
|
||||||
@@ -160,7 +164,7 @@ export class GoogleSheet {
|
|||||||
tempEntry[key] = inputData[rowIndex][columnIndex];
|
tempEntry[key] = inputData[rowIndex][columnIndex];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (Object.keys(tempEntry).length) {
|
if (Object.keys(tempEntry).length || addEmpty === true) {
|
||||||
// Only add the entry if data got found to not have empty ones
|
// Only add the entry if data got found to not have empty ones
|
||||||
returnData.push(tempEntry);
|
returnData.push(tempEntry);
|
||||||
}
|
}
|
||||||
@@ -312,6 +316,61 @@ export class GoogleSheet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Looks for a specific value in a column and if it gets found it returns the whole row
|
||||||
|
*
|
||||||
|
* @param {string[][]} inputData Data to to check for lookup value in
|
||||||
|
* @param {number} keyRowIndex Index of the row which contains the keys
|
||||||
|
* @param {number} dataStartRowIndex Index of the first row which contains data
|
||||||
|
* @param {ILookupValues[]} lookupValues The lookup values which decide what data to return
|
||||||
|
* @returns {Promise<IDataObject[]>}
|
||||||
|
* @memberof GoogleSheet
|
||||||
|
*/
|
||||||
|
async lookupValues(inputData: string[][], keyRowIndex: number, dataStartRowIndex: number, lookupValues: ILookupValues[]): Promise<IDataObject[]> {
|
||||||
|
const keys: string[] = [];
|
||||||
|
|
||||||
|
if (keyRowIndex < 0 || dataStartRowIndex < keyRowIndex || keyRowIndex >= inputData.length) {
|
||||||
|
// The key row does not exist so it is not possible to look up the data
|
||||||
|
throw new Error(`The key row does not exist!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create the keys array
|
||||||
|
for (let columnIndex = 0; columnIndex < inputData[keyRowIndex].length; columnIndex++) {
|
||||||
|
keys.push(inputData[keyRowIndex][columnIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnData = [
|
||||||
|
inputData[keyRowIndex],
|
||||||
|
];
|
||||||
|
|
||||||
|
// Loop over all the lookup values and try to find a row to return
|
||||||
|
let rowIndex: number;
|
||||||
|
let returnColumnIndex: number;
|
||||||
|
lookupLoop:
|
||||||
|
for (const lookupValue of lookupValues) {
|
||||||
|
returnColumnIndex = keys.indexOf(lookupValue.lookupColumn);
|
||||||
|
|
||||||
|
if (returnColumnIndex === -1) {
|
||||||
|
throw new Error(`The column "${lookupValue.lookupColumn}" could not be found!`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop over all the items and find the one with the matching value
|
||||||
|
for (rowIndex = dataStartRowIndex; rowIndex < inputData.length; rowIndex++) {
|
||||||
|
if (inputData[rowIndex][returnColumnIndex].toString() === lookupValue.lookupValue.toString()) {
|
||||||
|
returnData.push(inputData[rowIndex]);
|
||||||
|
continue lookupLoop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If value could not be found add an empty one that the order of
|
||||||
|
// the returned items stays the same
|
||||||
|
returnData.push([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.structureData(returnData, 1, keys, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
async convertStructuredDataToArray(inputData: IDataObject[], range: string, keyRowIndex: number): Promise<string[][]> {
|
async convertStructuredDataToArray(inputData: IDataObject[], range: string, keyRowIndex: number): Promise<string[][]> {
|
||||||
let startColumn, endColumn;
|
let startColumn, endColumn;
|
||||||
let sheet: string | undefined = undefined;
|
let sheet: string | undefined = undefined;
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import {
|
|||||||
import {
|
import {
|
||||||
GoogleSheet,
|
GoogleSheet,
|
||||||
IGoogleAuthCredentials,
|
IGoogleAuthCredentials,
|
||||||
|
ILookupValues,
|
||||||
ISheetUpdateData,
|
ISheetUpdateData,
|
||||||
} from './GoogleSheet';
|
} from './GoogleSheet';
|
||||||
|
|
||||||
@@ -44,6 +45,11 @@ export class GoogleSheets implements INodeType {
|
|||||||
value: 'append',
|
value: 'append',
|
||||||
description: 'Appends the data to a Sheet',
|
description: 'Appends the data to a Sheet',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: 'Lookup',
|
||||||
|
value: 'lookup',
|
||||||
|
description: 'Looks for a specific column value and then returns the matching row'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: 'Read',
|
name: 'Read',
|
||||||
value: 'read',
|
value: 'read',
|
||||||
@@ -150,7 +156,7 @@ export class GoogleSheets implements INodeType {
|
|||||||
},
|
},
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// Read & Update
|
// Read & Update & lookupColumn
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
{
|
{
|
||||||
displayName: 'Data Start Row',
|
displayName: 'Data Start Row',
|
||||||
@@ -194,6 +200,43 @@ export class GoogleSheets implements INodeType {
|
|||||||
description: 'Index of the row which contains the key. Starts with 0.',
|
description: 'Index of the row which contains the key. Starts with 0.',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
||||||
|
// ----------------------------------
|
||||||
|
// lookup
|
||||||
|
// ----------------------------------
|
||||||
|
{
|
||||||
|
displayName: 'Lookup Column',
|
||||||
|
name: 'lookupColumn',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'Email',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'lookup'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'The name of the column in which to look for value.',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
displayName: 'Lookup Value',
|
||||||
|
name: 'lookupValue',
|
||||||
|
type: 'string',
|
||||||
|
default: '',
|
||||||
|
placeholder: 'frank@example.com',
|
||||||
|
required: true,
|
||||||
|
displayOptions: {
|
||||||
|
show: {
|
||||||
|
operation: [
|
||||||
|
'lookup'
|
||||||
|
],
|
||||||
|
},
|
||||||
|
},
|
||||||
|
description: 'The value to look for in column.',
|
||||||
|
},
|
||||||
|
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// Update
|
// Update
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
@@ -259,6 +302,33 @@ export class GoogleSheets implements INodeType {
|
|||||||
// TODO: Should have something like add metadata which does not get passed through
|
// TODO: Should have something like add metadata which does not get passed through
|
||||||
|
|
||||||
return this.prepareOutputData(items);
|
return this.prepareOutputData(items);
|
||||||
|
} else if (operation === 'lookup') {
|
||||||
|
// ----------------------------------
|
||||||
|
// lookup
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
const sheetData = await sheet.getData(range);
|
||||||
|
|
||||||
|
if (sheetData === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
||||||
|
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||||
|
|
||||||
|
const items = this.getInputData();
|
||||||
|
|
||||||
|
const lookupValues: ILookupValues[] = [];
|
||||||
|
for (let i = 0; i < items.length; i++) {
|
||||||
|
lookupValues.push({
|
||||||
|
lookupColumn: this.getNodeParameter('lookupColumn', i) as string,
|
||||||
|
lookupValue: this.getNodeParameter('lookupValue', i) as string,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const returnData = await sheet.lookupValues(sheetData, keyRow, dataStartRow, lookupValues);
|
||||||
|
|
||||||
|
return [this.helpers.returnJsonArray(returnData)];
|
||||||
} else if (operation === 'read') {
|
} else if (operation === 'read') {
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
// read
|
// read
|
||||||
@@ -312,7 +382,6 @@ export class GoogleSheets implements INodeType {
|
|||||||
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
const keyRow = this.getNodeParameter('keyRow', 0) as number;
|
||||||
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
const dataStartRow = this.getNodeParameter('dataStartRow', 0) as number;
|
||||||
|
|
||||||
|
|
||||||
const setData: IDataObject[] = [];
|
const setData: IDataObject[] = [];
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
setData.push(item.json);
|
setData.push(item.json);
|
||||||
|
|||||||
Reference in New Issue
Block a user