Skip to main content

I've been trying to update a multipleCollaborator field without overwriting. Specifically I have a lookup field with user IDs and I'm trying to copy the same IDs (hence collaborators) to another (empty) collaborator field.

This should be relatively simple and yet i get a "TypeError: record.getCellValue is not a function or its return value is not iterable"

 
// This script downloads all the Auto-Requester's Collaborator IDs and re-prints them in Requester

const config = input.config()

const recordAT = config.recordAT

const autorequester = config.autorequester

const requester = config.requester

const table = base.getTable('Deliverables')



console.log(autorequester)



for (var arID of autorequester) {



let queryResult = await table.getView('All All').selectRecordsAsync({fields: ["Requester"]});

let record = queryResult.records.find(r => recordAT)

console.log(record.getCellValue("Requester"))



await table.updateRecordAsync(recordAT,

{

'Requester' : [

...record.getCellValue("Requester"),

{id: arID}

]

}

)

}

Airtable documentation says:

NOTE: When updating array-type fields (attachment, linked record, multiple select, multiple collaborators), you must set a new array of items. Whatever value you set will override the previous value. If you wish to append to the existing values in the cell, you can spread the current cell's items. For example:

updateRecordAsync(recordToUpdate, {

'Linked record field': [

...recordToUpdate.getCellValue('Linked record field'),

{id: 'recABC123xyz'}

]

});

Any help much appreciated!!

You should use queryResult.getRecord() instead of records.find(). Try console.log() on the queryResult.records object to see what's in it to know whether records.find(r => recId) will actually produce an object containing the getCellValue function or not.

Here's an example of how to get a record object:

//query the record

let table = base.getTable(tableId)

let queryResult = await table.selectRecordsAsync({fields: fieldNames})

let record = queryResult.getRecord(recId)

console.log(record.getCellValue("Requester"))

 

 

 

 

 


You should use queryResult.getRecord() instead of records.find(). Try console.log() on the queryResult.records object to see what's in it to know whether records.find(r => recId) will actually produce an object containing the getCellValue function or not.

Here's an example of how to get a record object:

//query the record

let table = base.getTable(tableId)

let queryResult = await table.selectRecordsAsync({fields: fieldNames})

let record = queryResult.getRecord(recId)

console.log(record.getCellValue("Requester"))

 

 

 

 

 


Thanks @Stephen_Orr1. getRecord() was a good suggestion, but the script was still throwing errors. The solution was much simpler, so for anyone looking to update Multiple Collaborator fields, this seems to be working just fine.

// This script copies a multiple collaborator field and copies into another one.

const config = input.config()

const recordAT = config.recordAT

const mCollaborator = config.mCollaborator

const newField = config.newField

const table = base.getTable('Deliverables')



console.log(mCollaborator)



//create an object of the multiple collaborator field

let mCollaboratorOBJ = []

for (let r in mCollaborator) {



mCollaboratorOBJ.push({id: mCollaborator[r]})



}



console.log(mCollaboratorOBJ)



//update the new Multiple Collaborator field

table.updateRecordAsync(recordAT,

{

'newField' : mCollaboratorOBJ

}

)

 


My reply was specifically addressing the error message mentioned: "TypeErrorrecord.getCellValue is not a function or its return value is not iterable" and not your entire code.

Re: your first method in the original post, getting all records in a table and then filtering down to your trigger record is unnecessary when Airtable gives us queryResult.getRecord(). Doing so also means we can't use getCellValue() as this is a specific method on the record object that is returned by getRecord(). (You can see this method isn't in queryResult.records, per my previous comment).

When converting an array of strings to an array of objects containing each of these strings, you can use JavaScript's array.map() function:

 

const newArray = autorequester.map(v => ({id: v}))

 

Then you can spread this newArray of value objects along with the requester's existing array of value objects when you go to update this field:

 

// This script downloads all the Auto-Requester's Collaborator IDs and re-prints them in Requester

const config = input.config();

const recordAT = config.recordAT;

const autorequester = config.autorequester;

const requester = config.requester;

const table = base.getTable('Deliverables');



//get requester field value

let queryResult = await table.getView('All All').selectRecordsAsync({ fields: ['Requester'] });

let record = queryResult.getRecord(recordAT);



await table.updateRecordAsync(recordAT, {

Requester: [...record.getCellValue('Requester'), ...autorequester.map(v => ({id: v}))],

});

 

For your second method, your for loop here is recreating the array.map() function. You can simplify this to:

 

// This script copies a multiple collaborator field and copies into another one.

const config = input.config()

const recordAT = config.recordAT

const mCollaborator = config.mCollaborator

const newField = config.newField

const table = base.getTable('Deliverables')



//update the new Multiple Collaborator field

await table.updateRecordAsync(recordAT, {

newField: mCollaborator.map(v => ({ id: v })),

})

 

Note: Your second method (which you accepted as the solution) overwrites the newField value which you stated in your original post you were trying to avoid.

For anyone who finds this, my second code block above contains the solution suggested by the docs re: not overwriting existing values.

Hope that helps!
-Stephen


My reply was specifically addressing the error message mentioned: "TypeErrorrecord.getCellValue is not a function or its return value is not iterable" and not your entire code.

Re: your first method in the original post, getting all records in a table and then filtering down to your trigger record is unnecessary when Airtable gives us queryResult.getRecord(). Doing so also means we can't use getCellValue() as this is a specific method on the record object that is returned by getRecord(). (You can see this method isn't in queryResult.records, per my previous comment).

When converting an array of strings to an array of objects containing each of these strings, you can use JavaScript's array.map() function:

 

const newArray = autorequester.map(v => ({id: v}))

 

Then you can spread this newArray of value objects along with the requester's existing array of value objects when you go to update this field:

 

// This script downloads all the Auto-Requester's Collaborator IDs and re-prints them in Requester

const config = input.config();

const recordAT = config.recordAT;

const autorequester = config.autorequester;

const requester = config.requester;

const table = base.getTable('Deliverables');



//get requester field value

let queryResult = await table.getView('All All').selectRecordsAsync({ fields: ['Requester'] });

let record = queryResult.getRecord(recordAT);



await table.updateRecordAsync(recordAT, {

Requester: [...record.getCellValue('Requester'), ...autorequester.map(v => ({id: v}))],

});

 

For your second method, your for loop here is recreating the array.map() function. You can simplify this to:

 

// This script copies a multiple collaborator field and copies into another one.

const config = input.config()

const recordAT = config.recordAT

const mCollaborator = config.mCollaborator

const newField = config.newField

const table = base.getTable('Deliverables')



//update the new Multiple Collaborator field

await table.updateRecordAsync(recordAT, {

newField: mCollaborator.map(v => ({ id: v })),

})

 

Note: Your second method (which you accepted as the solution) overwrites the newField value which you stated in your original post you were trying to avoid.

For anyone who finds this, my second code block above contains the solution suggested by the docs re: not overwriting existing values.

Hope that helps!
-Stephen


I think, brevity of ES6 would be incomplete without destructuring syntax 😁

// This script copies a multiple collaborator field and copies into another one.

const {recordAT, mCollaborator, newField} = input.config()

const table = base.getTable('Deliverables')



//update the new Multiple Collaborator field

await table.updateRecordAsync(recordAT, {

newField: mCollaborator.map(v => ({ id: v })),

})

  


You should use queryResult.getRecord() instead of records.find(). Try console.log() on the queryResult.records object to see what's in it to know whether records.find(r => recId) will actually produce an object containing the getCellValue function or not.

Here's an example of how to get a record object:

//query the record

let table = base.getTable(tableId)

let queryResult = await table.selectRecordsAsync({fields: fieldNames})

let record = queryResult.getRecord(recId)

console.log(record.getCellValue("Requester"))

 

 

 

 

 


Another hint, doesn't apply to the final solution, but might be useful. Airtable developers kindly added this method after several requests from community to avoid loading a table when you need just one record.
Instead of querying like this

//query the record

let table = base.getTable(tableId)

let queryResult = await table.selectRecordsAsync({fields: fieldNames})

let record = queryResult.getRecord(recId)

console.log(record.getCellValue("Requester"))

you can do

//query the record. No need to limit {fields: for a single record

let table = base.getTable(tableId)

let record = await table.selectRecordAsync(recId)

console.log(record.getCellValue("Requester"))


Reply