I can't figure this out: filtering RecordQueryResults gives me an empty Array

Hi folks

I have two tables: One is called “Products” the other is called “Product Components”. As you can imagine there is a (1:N) link between them, so a Product can have multiple Components. A Component has a single Product.

Here is what I am trying to do: I need to fetch all Components for a Product.

I have a RecordQueryResults called “allComponents”. product.id contains the Product I’m searching for. Here is my code:

let components = allComponents.records.filter(record => {
(record.getCellValue(“Product”).map(x => x.id).includes(product.id)) });

After this, if I check components.length I will get zero. It is an empty array.

I tried debugging using console.log inside my filter callback:

let components = allComponents.records.filter(record => {
console.log(record.getCellValue(“Product”).map(x => x.id).includes(product.id));
(record.getCellValue(“Product”).map(x => x.id).includes(product.id)) });

The results are: whenever a Product matches product.id I get TRUE; when it doesn’t I get FALSE. Therefore it would appear that the filter is working.

However, “components” is always an empty array…

Can anyone help me figure this out?

Welcome to the Airtable Community!

Your filter function doesn’t actually return anything. Your filter function checks if the cell value include the product id, but doesn’t actually return the value for the filter to use.

Option 1: Remove the curly braces. When there is only a single statement in the arrow function, the value of the statement is returned.

let components = allComponents.records.filter(record => 
record.getCellValue(“Product”).map(x => x.id).includes(product.id)

Option 2: Have an explicit return statement in the arrow function

let components = allComponents.records.filter(record => {
  let result = (record.getCellValue(“Product”).map(x => x.id).includes(product.id)) 
  return result

Note that the above options will throw an error if you have a component record that doesn’t belong to any products.

Option 3 (my preferred method): Get the records from the other side.
Since you state that product.id is the id of the product, I assume that product is the record for the product. I also assume that you know the name of the field with the linked components.

let componentsLinkedValue = product.getCellValue("Components")
let components = componentsLinkedValue.map(obj =>

If there is a possibility that there are no linked components you will also need to include a check for that.


Thank you! #1 worked like a charm. I will study #3 further as it is indeed a much more elegant solution.

1 Like

@kuovonne I have a question about your Option #3
I do have Product but it seems it is not a Record.
I have read from another Object called Quotes a cell called “Products” where we can select multiple Products in a Quote, but it seems the returned values are not records, but a collection of objects with Id and Name, but not all the Cells/Properties…

Here is what I did:

let products = currentQuote.getCellValue(“Products”)
for (let product of products) {
console.log(product.name) // this works fine
console.log(produc.id) // this works fine
console.log(product.getCellValues(“Product Components”)) // this does not work

Do you see anything I could do to actually get the Product Components from the Product Table linked attribute as you suggested?
At this time the only thing that occurs to me is reading the Product Table - but again I would have to use filter to find the correct product, so it would be basically the same as using Option #1 :wink:

Please, let me know if you have any other suggestions :slight_smile:

Ah, you have the value from a linked record field, not the actual product record itself. The linked record field value contains the id an “name” of the record, but no additional information, and now way to directly get any cell values.

It sounds like you are starting from the [Quotes] table and need to get [Components] which are two tables away, without actually need to get the product record itself.

In this case, I recommend going with option 1.

Awesome, thank you! :wink:

This topic was solved and automatically closed 3 days after the last reply. New replies are no longer allowed.