Skip to main content
Solved

Updating array-type fields in scripting (Multi Collaborator)


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!!

Best answer by Matteo_Cossu3

Stephen_Orr1 wrote:

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 } )

 

View original
Did this topic help you find an answer to your question?

5 replies

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"))

 

 

 

 

 


  • Author
  • Inspiring
  • 15 replies
  • Answer
  • June 19, 2023
Stephen_Orr1 wrote:

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


Alexey_Gusev
Forum|alt.badge.img+12
Stephen_Orr1 wrote:

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 })), })

  


Alexey_Gusev
Forum|alt.badge.img+12
Stephen_Orr1 wrote:

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