Last active
June 14, 2024 03:53
-
-
Save on2air/b68450a877ab99fe4a93ef7f9c387568 to your computer and use it in GitHub Desktop.
Same Table Backlinks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/***** | |
* Title: Same Table Backlinks | |
* License: MIT | |
* Author: Openside (Team behind On2Air products and BuiltOnAir community) | |
* Sites: | |
* https://openside.com - Openside Consulting Services | |
* https://openside.com/#products - On2Air Products | |
* https://builtonair.com - All things Airtable Community | |
* | |
* Reach out for all your Airtable needs | |
* | |
* Explainer Video: https://www.loom.com/share/9f90bb7bf95b4581a12a9750edb3a376 | |
* | |
* Description: Typically when creating a Linked Records to another table, | |
* it will auto-create a field on the other table holding the backlinks back to the current table. | |
* However, when creating links within the same table, it does not generate the 2nd backlink field. | |
* | |
* This script will do that for you. This is useful to see where a single table linked record field | |
* is in use within the same field. | |
* | |
* Instructions: Configure the links array below with the information to generate the links. | |
* If no links are configured, it will ask for user input, so its ok to leave blank. | |
* | |
* The 3 configuration items are: | |
* table: The table name containing the linked record | |
* view: (Optional) if set, then will filter records to check based on the view | |
* source: The field name that is a linked record to the same table that is what | |
* you are already updating. This field does not get modified. | |
* dest: The destination field that will determine all the places each record is used as a source. | |
* This field will get replaced each time script is ran | |
* | |
*/ | |
//-------------START CONFIGURATION ------------------// | |
let links = [ | |
// { | |
// table:"Family Tree", | |
// view: '', | |
// source:"Parents", | |
// dest:"Children" | |
// }, | |
// { | |
// table:"Family Tree 2", | |
// source:"Parents", | |
// dest:"Children" | |
// } | |
] | |
//-------------END CONFIGURATION ------------------// | |
if(!links || !links.length){ | |
output.markdown("## Select Your Settings to Setup Children Links") | |
let table = await input.tableAsync("Select The table") | |
let source = await input.fieldAsync("Select The Source Field",table.id) | |
let dest = await input.fieldAsync("Select The Destination Field",table.id) | |
links.push({table:table.id,source:source.name,dest:dest.name}) | |
} | |
const syncLinks = async( tableId, source, dest, viewName = '' ) => { | |
let table = base.getTable(tableId) | |
output.markdown(`#### Syncing - '${table.name}': '${source}' -> '${dest}'`) | |
let view = viewName ? table.getView(viewName) : null | |
let recordsFull = view ? await view.selectRecordsAsync() : await table.selectRecordsAsync() | |
let records = recordsFull.records | |
let len = records.length | |
const findChildren = async() => { | |
let tree = {} | |
const setTree = ( parent, kid) => { | |
if(!tree[parent])tree[parent] = [] | |
tree[parent].push({id:kid}) | |
} | |
for(let t=0;t<records.length;t++){ | |
let rec = records[t] | |
if (!tree[rec.id]) tree[rec.id] = [] | |
let parents = rec.getCellValue(source) | |
if(!parents)continue; | |
for(let p=0; p<parents.length; p++){ | |
setTree(parents[p].id, rec.id) | |
} | |
} | |
output.text("------------------------------------") | |
let parentKeys = Object.keys(tree) | |
let queue = [] | |
for(let i=0; i<parentKeys.length; i++){ | |
let pKey = parentKeys[i] | |
let pRecord = await recordsFull.getRecord(pKey) | |
let kids = tree[pKey] | |
if((!kids || kids.length === 0) && (!pRecord.getCellValue(dest) || pRecord.getCellValue(dest).length === 0))continue | |
queue.push({id:pKey,fields:{[dest]: kids || []}}) | |
if(queue.length === 50){ | |
await table.updateRecordsAsync(queue) | |
output.text("... "+(i+1)) | |
queue = [] | |
} | |
} | |
if(queue.length){ | |
await table.updateRecordsAsync(queue) | |
output.text("... "+ parentKeys.length) | |
queue = [] | |
} | |
} | |
await findChildren() | |
} | |
output.clear() | |
output.markdown("## Table Syncing Starting....") | |
for(let l=0; l<links.length;l++){ | |
let link = links[l] | |
await syncLinks( link.table, link.source, link.dest, link.view || '' ) | |
} | |
output.markdown("### Syncing Completed.") | |
//THIS WAS FOR GENERATING THE PARENT LINKS//TESTING ONLY// | |
// const getRandomInt = (max) => { | |
// return Math.floor(Math.random() * Math.floor(max)); | |
// } | |
// const setParents = async() => { | |
// for(let t=0;t<records.length;t++){ | |
// let rec = records[t] | |
// let parents = [] | |
// let otherParent = -1 | |
// while(parents.length < 2){ | |
// let pIndex = getRandomInt(len) | |
// if(pIndex != t && pIndex !== otherParent){//cant be your own parent or have 2 of same | |
// parents.push({id:records[pIndex].id}) | |
// otherParent = pIndex | |
// } | |
// } | |
// await table.updateRecordAsync(rec.id,{ | |
// [SOURCE_FIELD]:parents | |
// }) | |
// } | |
// } | |
// //await setParents() |
Any fix for this issue?
Error
TypeError: output.clear is not a function
at main on line 116
I am running this as part of an Automation
@on2air
Sorry to pester you - do you see any way to fix the error in my last comment?
Would there be a way to do this but have multiple sources linking to a single destination?
If I am reading this correctly, this will only create links, it won't delete them. So if you delete a link in record A pointing to B, then B's link back to A won't ever be deleted.
A fixed version of this that is intended for automations is in my gist here.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi, I have what's probably a dumb question. I used this code in my Airtable script extension with no problem, but when I tried to build an Airtable automation, I get an error message that says "TypeError: output.clear is not a function" and the same thing for output.markdown. Any advice?