Help

Code to retrieve url in Attachments field

Topic Labels: API
14759 13
cancel
Showing results for 
Search instead for 
Did you mean: 
DanielAssayag
6 - Interface Innovator
6 - Interface Innovator

Hi,
Here is my code using record.get([“Attachments”]); :

function showListe() {
  base("Works")
    .select({ view: "Grid view" })
    .eachPage(function page(records) {
      records.forEach(function(record) {
        var li = document.createElement("li");  
        li.textContent = record.get(["Attachments"]);
        document.getElementById("root").appendChild(li);
      });
    });
}

which gets me :

  • [object Object]
  • [object Object]

If i do record.get([“Attachments”][“url”);
i get nothing…

Help!

13 Replies 13

Hi @DanielAssayag - in the API, an attachments field is an array of objects, so you need to:

  • do a “for each” on the array and, in the loop, access:

['Attachments'][i]['url']

for each i

  • Or, if you know you want the first attachment or if there’s only one attachment, access:

['Attachments'][0]['url']

JB

DanielAssayag
6 - Interface Innovator
6 - Interface Innovator

Thanks,
I still can’t make it work but it might be my code.

What about retrieving the Attachments id, or width?

Unfortunately, you’ve got the same issue. Even with one attachment, the API returns an array (in this case with one object):

[
    {
        "id": "att911J3Ml..OF2l",
        "url": "https://dl.airtable.com/.attachments/117bac5e63..466918/5e2ad89d/Screenshot2019-09-05at16.23.21.png",
        "filename": "Screenshot 2019-09-05 at 16.23.21.png",
        "size": 32212,
        "type": "image/png",
        "thumbnails": {
            "small": {
                "url": "https://dl.airtable.com/.attachmentThumbnails/bac00690d..b31218/81919b8a",
                "width": 119,
                "height": 36
            },
            "large": {
                "url": "https://dl.airtable.com/.attachmentThumbnails/6937346c0d5..37d8e5/9a38e7bb",
                "width": 1094,
                "height": 330
            },
            "full": {
                "url": "https://dl.airtable.com/.attachmentThumbnails/9747be1d8c7..558f689c89/7e632201",
                "width": 3000,
                "height": 3000
            }
        }
    }
]

So you’ve still got to loop through the array and use the array index to get anything

Out of interest why are you doing record.get there? Isn’t it something like:

record.Attachments[0].url

I’m assuming you’re in JS there and I’m only a moderately good coder, so I might be talking out of my hat!

DanielAssayag
6 - Interface Innovator
6 - Interface Innovator

I dont know why, but i can get the * [object Object]
but when i use [0][“url”] it just returns nothing.

How do you retrieve the all the raw json data on the object?

Here is my current code, i’m using codesandboxio in react js to run my tests.

import React from "react";
import ReactDOM from "react-dom";

import "./styles.css";

var $ = require("jquery");

var Airtable = require("airtable");
Airtable.configure({
  endpointUrl: "https://api.airtable.com",
  apiKey: "xx"
});
var base = Airtable.base("xx");

function App() {
  return (
    <div className="App">
      <div id="artworks">{loadArtworks()}</div>
    </div>
  );
}

var loadArtworks = function() {
  $("#artworks").empty();
  base("Works")
    .select({
      sort: [
        {field: 'Year', direction: 'asc'}
    ]
    })
    .eachPage(
      function page(records, fetchNextPage) {
        records.forEach(function(record) {
          var works = $("<div>");
          works.append($("<h3 class='name'>").text(record.get("Name")));
          works.append($("<div class='year'>").text(record.get(["Year"])));
          works.append($("<div class='typeofwork'>").text(record.get(["Type of work"])));
          works.append($("<div class='dimensions'>").text(record.get(["Dimensions (cm)"])));
          // nextline: this return [object Object]
          works.append($("<div class='photos'>").text(record.get(["Photos"]))); 
          // nextline: this return nothing
          works.append($("<div class='photosurl'>").text(record.get(["Photos"][0]["url"]))); 
          
          works.attr("id", record.getId());
          $("#artworks").append(works);
        });
        fetchNextPage();
      },
      function done(error) {
        console.log(error);
      }
    );
};

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
DanielAssayag
6 - Interface Innovator
6 - Interface Innovator

I was able to retrieve the json:

Here is the structure of my data :

Screenshot 2019-09-05 at 23.48.09.png

but i don’t know how to retrieve the data inside the “Photos” field (attachment type)

Um… assuming Photos is the name of the attachment-type field, the url of the first photo in the array should be…

Photos[0].url

You are not obligated to enumerate the collection of attachments in a field of type [attachment], but it is good practice because you really don’t know if there’s none, one, or more photos. Assuming Photos[0]. … is valid will be brittle and often may fail.

Whenever you see this, it’s an indication that each item in the array is javascript object notation (JSON) and it is addressable like any other JSON objects.

If you need to understand what’s inside that object, you can use JSON.parse() and JSON.stringify() to expose the data. But the dudes at Airtable have also provided stellar API documentation that will expose the attachment format as well.

Make sense?

It does,
Though i still have issues retrieving attachments (sorry for that)

Here is a function i coded to retrieve data, but i can only console.log ther records and not return it in variable to parse it json. Any idea how to do it?

function loadGeneralItems(table) { 
var recList = []
    base(table).select().all()
    .then(
       function (records)  { 
        for (let i=0; i< records.length; i++)
       recList.push(records[i]._rawJson.fields) 
      // console.log(recList) // outputs ([Object, ...])
      }); 
   // return recList // returns nothing         
}

If you are loading all the records in a table and then enumerating them only to build yet another array representing the same records, I must ask why? Why not simply return records? It is an array with all of the data - even the data that is in nested objects such as fields of type attachment.

I suspect the answer is that you are groping to find a way to access the data in your attachments. That said, allow me to demonstrate how I approach this in server-side javascript (using Google Apps Script) WITHOUT using the Airtable SDK which I believe you are using.

At the outset, there’s nothing wrong with the Airtable SDK, but because it attempts to [quietly] overcome shortfalls in the API (such as true queries), I tend to develop 100% of the code required to extract Airtable data. Color me “old-school” in this example. :winking_face:

For this guide, I’ll use the Airborne Search Configuration table because it contains one record with an attachment which is a 1mb ElasticSearch index document which is a full-text index of many other bases. The field IndexRef is a field of type attachment and I know that extracting values from these field types if your key challenge. Here’s what the table looks like.

image.png
As a simple starting point, consider the following function - it returns only the first page of a table (just 100 records). Passing the baseKey, tableName, and apiKey to this function returns the records as JSON text.

image.png
While the response is JSON, it is not parsed. More on that later.

Now, take a close look at this simple example that uses the API function call to get 100 records and enumerate them.

image.png
It will return a collection of records like this one:

image.png
What’s happening in the enumRecords function?

  • Line 38 retrieves a list of records in JSON format (as text).
  • Line 43 parses the JSON results text into an array of records. Note - .records is added outside the parsing function because we really only want the records node which is not accessible until we first parse the results.
  • The enumeration of the records filters for a record where IndexRef is not undefined (see line 52).
  • At line 56 we log the stringified version of the record so we can easily examine it in a JSON parser (if we want).
  • Finally, line 59 logs the attachment url value.

And the log output looks something like this:

image.png
Final Thoughts

Note how this example doesn’t have to build a new array consisting of the data to get at the attachment data. In fact, the promise of JSON is that – aside from the parsing step – it is readily consumable as soon as your app has it.

Also note the direct access to all the fields in the attachment collection; accessing this data should be no different than accessing any other data. I suspect the SDK does this for you, but it seems that its integrated helper methods is what may be confusing you. I’m also certain that using the SDK, you can build a better version of my training code and likely with fewer lines. I don’t use the SDK so I don’t have any demo code to share with you.

Lastly, as I’m sure someone will type in the attachment URL to snoop on it, I’ll save you the trouble. It’s a Lucene-inspired full text index of the demo bases in Airtable and it is fully accessible without credentials because all Airtable attachment URLs are open and accessible to everyone. :winking_face: Ergo, be very careful when you expose attachment URLs in any context - they are public documents.

Matthew_Katz
4 - Data Explorer
4 - Data Explorer

I worked through this on my own, here is my hobbyist solution… good is good enough, right?

// get the entire attachments data… everything
var urldata = [record.get(‘Attachments’)];

// stingify the data into one messey long piece of text.
var urldata2 = JSON.stringify(urldata);

// split the string into an array using an apostrophe (you need \" in the quotes)
var urldata3 = urldata2.split("\"");

// publish the URL so that I can make my link reference.
Format.href = urldata3[7];

EASY as PIE - Works in any Setup… good luck fellow coders :slightly_smiling_face:

Juan_Pablo
4 - Data Explorer
4 - Data Explorer

@Bill.French I am working in Google Scripts trying to send all of my data to a google sheet but the 100 records limit is killing me. I see you put here a method to extract the first hundred, do you have the iterative function to go on?

Sure.

//
// get airtable records
//
function atGetTable_(baseID, tableName, apiKey)
{

  // set the key if not passed in the argument
  apiKey = (apiKey == undefined) ? airtableAPIKey : apiKey;

  // create the urlfetch options object
  const options = {
    method: 'GET',
    headers: {
      'Authorization' : 'Bearer ' + apiKey,
      'Content-type': 'application/json'
    },
    muteHttpExceptions : true
  };
  
  // setup the page loop
  var offSet = true;
  var currentPage = 0;
  var aRecords = [];
  var offsetParameter = "";

  // iterate across the pages
  while (offSet)
  {

    // log the page number to the console
    Logger.log("Reading page " + currentPage);

    // call the airtable api
    var response = UrlFetchApp.fetch(airtableAPIEndpoint + baseID + "/" + encodeURIComponent(tableName) + "?pageSize=100" + offsetParameter, options).getContentText();
    
    // concat the array for of records for the current page 
    aRecords = aRecords.concat(JSON.parse(response).records);
    var offSet = JSON.parse(response).offset;

    // is there more data?
    if (offSet)
    {
      offsetParameter = "&offset=" + encodeURIComponent(offSet);
    } else {
      break;
    }

    // increment the page number
    currentPage += 1;
  }
  
  var oRecords = {
    "records" : aRecords
  }
  
  return(JSON.stringify(oRecords));
  
}
Jaydeep_Gajera
4 - Data Explorer
4 - Data Explorer

This seems hacky but worked for me.

${JSON.parse(JSON.stringify(record.get([‘Image’][0])))[0][‘url’]}