Help

Re: TypeError: newRecordId.getCellValue is not a function

2977 1
cancel
Showing results for 
Search instead for 
Did you mean: 
Airtable_admin
5 - Automation Enthusiast
5 - Automation Enthusiast

Hi all, I’m trying to link my a “parent” record to new created records in a script following this source. But I keep on getting the error “TypeError: newRecordId.getCellValue is not a function”.

The code can be found under " /Link the new record (child) to the parent record/".

Thanks for the help in advance… it’s very much appreciated!

let inputConfig = input.config();

let table = base.getTable('Progress General Indicator 🚫');
let projectsTable = base.getTable('Projects 🖌');

let indicators = inputConfig.linkedIndicatorIDs;
let projectID = inputConfig.projectID;
let recordID = inputConfig.recordID;
let linkedIndicators = inputConfig.linkedIndicators;

/*Create new records (children)*/
for (let indicator of indicators) {
    console.log(`Adding indicator ${indicator} to the new record.`);
    console.log(`Adding project ${projectID} to the new record.`);

    let newRecordId = await table.createRecordsAsync([
        {
            fields: {
                /*'Projects 🖌': [{id: projectID}],*/
                'General indicators 🖌': [{id: indicator}]
            }
        }
    ])
    console.log(`Added record ${newRecordId}.`);

    /*Link the new record (child) to the parent record*/
    let existingLinkedRecords = newRecordId.getCellValue('Optional: Link to other indicators');
    table.updateRecordAsync(recordID, {'Optional: Link to other indicators': [existingLinkedRecords,{ id: newRecordId.id }]})

} 

Capture

6 Replies 6
Airtable_admin
5 - Automation Enthusiast
5 - Automation Enthusiast

Further optimized the script but the error is now "TypeError: parent[0].getCellValue is not a function or its return value is not iterable
** at main on line 57"**

/*Script is written by Pello Mugica Gonzalez. Email: mugicagonzalez.pello@gmail.com*/

let inputConfig = input.config();

let table = base.getTable('Progress General Indicator 🚫');
let projectsTable = base.getTable('Projects 🖌');

let indicators = inputConfig.linkedIndicatorIDs;
let projectID = inputConfig.projectID;
let projectID2 = projectID[0];
let recordID = inputConfig.recordID;
let linkedIndicators = inputConfig.linkedIndicators;

/*Create new records (children)*/
for (let indicator of indicators) {
    console.log(`Adding indicator ${indicator} to the new record.`);
    console.log(`Adding project ${projectID2} to the new record.`);

    let newRecordId = await table.createRecordsAsync([
        {
            fields: {
                'Projects 🖌': [{id: projectID2}],
                'General indicators 🖌': [{id: indicator}]
            }
        }
    ])
    
/*Link the new record (child) to the parent record*/

    /*Reload table (not sure if necessary) and select all records in table to filter*/
    let table2 = base.getTable('Progress General Indicator 🚫');
    let query = await table2.selectRecordsAsync();

    /*Make vector a single string (id of record) */
    let newRecordId2 = newRecordId[0];
    console.log(`Added record ${newRecordId2}.`);

    /*Filter out the child record */
    let child = query.records.filter(record => {
    return record.id == newRecordId2
    });

    /*Filter out the parent record */
    let parent = query.records.filter(record => {
    return record.id == recordID
    });
    
    console.log(`Found child ${child[0].id}`);
    console.log(`Found parent ${parent[0].id}`);


    table.updateRecordAsync(recordID, {
        'Optional: Link to other indicators': [
            ...parent[0].getCellValue('Optional: Link to other indicators'),
            { id: child[0].id }
        ]
    })

}

In both scripts you’re trying to get cell values from the record ID, not the “whole record” object.

In your second script, get rid of the .filter(...) for the parent variable

Thanks for the help! I made it work like this now

/*Script is written by Pello Mugica Gonzalez. Email: mugicagonzalez.pello@gmail.com*/

let inputConfig = input.config();

let table = base.getTable('Progress General Indicator 🚫');
let query = await table.selectRecordsAsync();
let projectsTable = base.getTable('Projects 🖌');
let projectID = inputConfig.projectID;
let projectID2 = projectID[0];
let recordID = inputConfig.recordID;
let linkedIndicators = inputConfig.linkedIndicators;

/*Filter out the parent record */
let parent = query.records.filter(record => {
    return record.id == recordID
});

console.log(`Found indicators ${parent[0].getCellValue('Project indicators 🚫 (from General indicators 🖌)')} to be added.`);

/*Find linked projects (via lookup)*/
let indicators = parent[0].getCellValue('Project indicators 🚫 (from General indicators 🖌)');

console.log(`Found indicators ${indicators} to be added.`);

/*Create new records (children)*/
for (let indicator of indicators) {
    console.log(`Adding indicator ${indicator} to the new record.`);
    console.log(`Adding project ${projectID2} to the new record.`);

    let newRecordId = await table.createRecordsAsync([
        {
            fields: {
                'Projects 🖌': [{id: projectID2}],
                'General indicators 🖌': [{id: indicator}]
            }
        }
    ])
    
    /*Link the new record (child) to the parent record*/

    /*Reload table (not sure if necessary) and select all records in table to filter*/
    let table2 = base.getTable('Progress General Indicator 🚫');
    let query2 = await table2.selectRecordsAsync();

    /*Make vector a single string (id of record) */
    let newRecordId2 = newRecordId[0];
    console.log(`Added record ${newRecordId2}.`);

    /*Filter out the child record */
    let child = query2.records.filter(record => {
        return record.id == newRecordId2
    });

    /*Filter out the parent record */
    let parent2 = query.records.filter(record => {
        return record.id == recordID
    });
    
    console.log(`Found child ${child[0].name}`);
    console.log(`Found parent ${parent2[0].name}`);


    if(parent2[0].getCellValue('Optional: Link to other indicators') != null) {
        table2.updateRecordAsync(recordID, {
        'Optional: Link to other indicators': [
            ...parent2[0].getCellValue('Optional: Link to other indicators'),
            { id: child[0].id }
        ]
    })
    }

    table2 = null;
    query2 = null;
    child = null;
    parent2 = null;
} 









The only issue that I still have now is that I want to link all the new created records back to the “parent” record. That is what happens in the last IF statement. But there’s something wrong in my FOR loop, because eventually when a second indicator is added, the last added one gets replaced by the new one while I actually want them all to be linked. It feels like the system doesn’t overwrite my parent instance and only remembers the original record’s values. That why I tried to reset them at the end of the loop but that didn’t help either. Do you see what’s wrong here?

Hi,
it feels like a bit “over-engineering”. When you called array a vector, I realized that you are trying to use approach from other programming language.
in JS, some things are much more simple

to be honest, I can’t understand at 100% what and where you are linking. If we talking about linking records in 2 different tables, you should just set ‘link to parent’ in a {fields: '... 'link field': {id: parentID}... } object at the record creation moment and that’s all. Back link from parent will be created automatically.
If you are linking into the same table, you need to set links for both ways.

cell value of a linked record is array of objects {id: recXXXXX}, where recXXXX is/are id(s) of linked record(s). if it contains zero or single value, it’s still array, empty [] or containing single element.

instead of using

let query = await table.selectRecordsAsync();
.....
let parent = query.records.filter(record => {
    return record.id == recordID
});

you can directly get a single record:
let parent = await table.selectRecordAsync(recordID);

your usage of createRecordsAsync is not quite correct, it’s a method to create several records in a single call, which returns array of IDs (of new created records)
also, you wrapped the rest of your code inside the loop for (let indicator of indicators) {
and forget to set await before table2.updateRecordAsync, that’s why it’s behavior is such unpredictable.

usually it should be something like

let createArray=[]
for (let indicator of indicators) {
    console.log(`Adding indicator ${indicator} to the new record.`);
    console.log(`Adding project ${projectID2} to the new record.`);
    createArray.push({
            fields: {
                'Projects 🖌': [{id: projectID2}],
                'General indicators 🖌': [{id: indicator}]
            }
        }
}
let newRecordIdS= await table.createRecordsAsync(createArray)

with new syntax including ‘arrow-functions’ and ‘object destructuring’ some things are much easier.
now i’m not using loops (almost) and trying to avoid unnecessary efforts.

let create=ind=>{fields: {'Projects 🖌': [{id: projectID2}] , 'General indicators 🖌': [{id: ind}] }
let createArr=indicators.map(create)
let newRecordIdS= await table.createRecordsAsync(createArr)

to update a parent record, you just need a single operation, but I would put following lines somewhere at the beginning (alias for long fieldnames are useful, when you change name of a field, you don’t need to jump through all the code later. Uppercase is far from recommended best practices, but I just like how it highlighted in AT code editor, so I can quickly detect fields in it. You can do it in your own way)

let [SOURCE, TARGET]=['Project indicators 🚫 (from General indicators 🖌)','Optional: Link to other indicators']
let linkObj=link=>( {'id':link} )
let {indicators,projectID,recordID,linkedIndicators}=inputConfig
/* the last instead of
  let indicators = inputConfig.linkedIndicatorIDs;
let projectID = inputConfig.projectID;
let recordID = inputConfig.recordID;
let linkedIndicators = inputConfig.linkedIndicators; 

you can even omit extra variable and write
let {indicators,projectID,recordID,linkedIndicators}=input.config()
 */

and then (this should be somewhere at the end of code)
await table.updateRecordAsync(recordID, { [TARGET]: [...parent.getCellValue([TARGET]),...newRecordIdS.map(linkObj)]})

I hope it will help you and you will be able to set it to right place and make your code work as expected.

Wow, thanks a lot Alexey! I got to learn a lot from your reply, and it made the script work indeed as I wanted. Gotta love the Airtable community :slightly_smiling_face: . Issue solved! Thanks again!

Hi,
I suppose you mark this answer as “Solution”, and probably add your final working version, so in future community visitors encountering the same error, can easier find this thread.