Question

Get More Than 1 Record in CSV File from Knack

  • 24 October 2023
  • 9 replies
  • 86 views

Badge

I am trying to create a ZAP where I retrieve scanned documents from Docparser, save the PDF to Google Drive and then create a CSV file in Google Drive from the records created in the Knack DB. I am creating the Knack DB records when Docparser scans the files. 

I have everything working except creating the CSV. When Zapier writes the CSV to Google Drive, it creates a separate CSV file for each record. I am trying to get it to write multiple records into the same CSV file so I can use the CSV to load records into another system. I have tried EasyCSV and Google Drive create CSV and they always write 1 record per CSV file. 

I am trying to figure out how to get multiple records written to one file. I just need to grab all records from Knack where the field called CSVCREATED = N. I have tried doing a Knack record lookup but that doesn’t work because you can only lookup by the record ID #. I understand a loop may work but not completely sure. 

I am simply trying to read multiple records from a Knack table where CSVCREATED=N and write those records to 1 CSV file. Can someone tell me how I can accomplish this? 

Thank you in advance. 


This post has been closed for comments. Please create a new post if you need help or have a question about this topic.

9 replies

Userlevel 7
Badge +14

Hi @smccarthy956 

Good question.

To help us have context, please post screenshots with how your Zap steps are configured.

Badge

The steps are below. Basically, I am pulling all PDF documents from Docparser that get processed and then exporting them to Google Drive as a txt file. Each single PDF gets exported as a separate text file because Docparser processes every file as a separate document. I am trying to combine all the CSV records into one file which seems very difficult. I have a batch file on the system combining them right now but would like to find a way to do it Zapier if possible. 

All the records get saved into Knack so I would think it would be easy to tell Zapier to download all records with a specific variable in the database but I can’t seem to do that either. Why is it so difficult to download records to a combined CSV?

See below: 

 

Step 1: 

Step 2:

 

Step 3: 

 

Userlevel 7
Badge +14

@smccarthy956 

These are the available Knack Zap actions.

If you are trying to do a search to return multiple records, then you’d likely have to explore using the Knack API: https://docs.knack.com/docs/retrieving-multiple-records

You can use the AI assist in the Zap action: Knack - App Extensions

 

 

Badge

I can to this. I hope in the future that there is a way to download multiple records from the DB without having to use an API. Thank you. 

Badge

OK, so I was able to write the API and pull records from the table which works great. A few more questions if you don’t mind: 

  1. Can I build a step in Zapier to run the API to get the records? If so, which app in the ZAP do I use to use the API script? I am using Python right now to execute it to test it. 
  2. If I build the API script into the ZAP to pull the records, will these records be available in the ZAP for other steps? Will it keep the records to incorporate into other steps of the ZAP. For example, when I pull 5 records from Docparser, those 5 records are usable in other steps of the process. If the API script pulls 10 records, can I then use those records in other steps in the ZAP? 
  3. Is it possible to have the API script pull the field names? I tried doing so and I get the ID (auto increment) field header name back but everything else is called field_1, field_2, etc. Is it possible to have the API script pull down all the field names? 

 

This is the script I currently wrote to return all records from the invoices table:

import requests
import csv

# Knack API endpoint and headers
BASE_URL = "https://api.knack.com/v1/objects/object_1/records"
HEADERS = {
    "Content-Type": "application/json",
    "X-Knack-Application-Id": "xxx", 
    "X-Knack-REST-API-Key": "xxx"
}

def get_all_records():
    all_records = []
    page_number = 1

    while True:
        response = requests.get(BASE_URL, headers=HEADERS, params={'page': page_number})
        
        if response.status_code != 200:
            print(f"Failed to fetch data on page {page_number}. Status code: {response.status_code}, Response text: {response.text}")
            break
        
        records = response.json().get("records", [])
        
        if not records:
            break

        all_records.extend(records)
        page_number += 1

    return all_records

def save_records_to_csv(records, filename="knack_data.csv"):
    if not records:
        print("No records to save.")
        return

    # Exclude fields ending with "_raw"
    filtered_keys = [key for key in records[0].keys() if not key.endswith("_raw")]

    with open(filename, 'w', newline='', encoding='utf-8') as csv_file:
        writer = csv.DictWriter(csv_file, fieldnames=filtered_keys)
        writer.writeheader()
        for record in records:
            writer.writerow({key: record[key] for key in filtered_keys})

    print(f"Data saved to {filename}")

if __name__ == "__main__":
    records = get_all_records()
    save_records_to_csv(records)

 

Thank you again for all your help. This is the first post where I got a clear answer as to how to pull records from the Knack table to a CSV. This is excellent. If you can help me with the above questions, I will be very grateful!

Badge

FYI - this is a good script for anyone to use to pull records from your Knack DB. All you need to do is change the following:

BASE_URL = "https://api.knack.com/v1/objects/object_1/records"

Change this line and put in your proper object ID (IE.object_1). The object ID can be found in the address bar: 

The just make sure you put in your APPLICATION ID and API KEY in those two lines and you are good. Those can be found in your SETTINGS in Knack. You can replace the XXX in this script with both. 

This script is designed to pull all records from the object you specify and then download them into a CSV file. I am excluding the RAW fields and only pulling the regular fields. This script will work with any table as long as you specify the object ID. 

I hope this helps people with little coding knowledge to be able to download records from your Knack table to a CSV file. You can also add specific values to download only specific records (IE. Field 2 = NO). 

Userlevel 7
Badge +14

@smccarthy956 

App APIs can be used in Zaps via the apps:

 

There are 2 Knack actions available for using the Knack API.

  • App Extensions
  • API Request

 

Badge

Thanks. I figured out how to download the headers. This script is pulling all the records I need, downloading the headers and limiting the records downloaded to CSV Created = N. So I am assuming I want to use the KNACK API REQUEST to run this as that sounds like it’s the most logical choice. 

So if I use the KNACK API REQUEST I am assuming the Knack records will be available in other processes correct? I have to assume since the API is calling the records you want I can then use those records in future process steps. Is this a correct assumption? 

Thank you very much for your help. It was very informative and I learned a lot building the API and reading the feedback on the forum. This solves my major issue of getting all the records into one properly formatted CSV file. This solves my problem after 2 months of trying!! 

If you can let me know if the records will be available in the ZAP process after the API call, I will greatly appreciated it. I have to assume so but I want to confirm. 

The script is below for anyone who is trying to figure out how to pull records out of Knack and writing them to a CSV file. I have figured out all the logic of how to pull the proper header files, writing it to the CSV matching the database field order, excluding fields and pulling records based on a specific criteria.

This API script should cover 95% of everything anyone wants to do with pulling Knack records: 

import requests
import csv
import json

# Knack API endpoint and headers - Change the Object ID to your Knack Object ID
BASE_URL = "https://api.knack.com/v1/objects/object_1/records"
HEADERS = {
    "Content-Type": "application/json",
    "X-Knack-Application-Id": "put your app id here", 
    "X-Knack-REST-API-Key": "put your API key here"
}

# List of fields to exclude from downloading
EXCLUDED_FIELDS = ["id", "field_50", "field_46", "field_1", "field_30", "field_49","field_26"]

def fetch_field_metadata():
    response = requests.get(f"https://api.knack.com/v1/objects/object_1", headers=HEADERS)
    metadata = response.json().get("object", {}).get("fields", [])
    print("Field Metadata:", json.dumps(metadata, indent=4))  # Print the field metadata for debugging
    return metadata

def get_header_mappings():
    field_metadata = fetch_field_metadata()
    return {field["key"]: field.get("name", field["key"]) for field in field_metadata}

def get_all_records():
    all_records = []
    page_number = 1
    filter_param = {
        "match": "and",
        "rules": [{
            "field": "field_49",
            "operator": "is",
            "value": "N"
        }]
    }

    while True:
        response = requests.get(
            BASE_URL, 
            headers=HEADERS, 
            params={'page': page_number, 'filters': json.dumps(filter_param)}
        )
        if response.status_code != 200:
            print(f"Failed to fetch data on page {page_number}. Status code: {response.status_code}, Response text: {response.text}")
            break
        records = response.json().get("records", [])
        if not records:
            break
        all_records.extend(records)
        page_number += 1

    return all_records

def save_records_to_csv(records, headers_mapping, filename="knack_data.csv"):
    if not records:
        print("No records to save.")
        return
    # Filter out excluded fields
    header_labels = [headers_mapping.get(key, key) for key in records[0].keys() if key not in EXCLUDED_FIELDS and not key.endswith("_raw")]
    with open(filename, 'w', newline='', encoding='utf-8') as csv_file:
        writer = csv.DictWriter(csv_file, fieldnames=header_labels)
        writer.writeheader()
        for record in records:
            # Exclude fields in EXCLUDED_FIELDS
            writer.writerow({headers_mapping.get(key, key): record[key] for key in record.keys() if key not in EXCLUDED_FIELDS and not key.endswith("_raw")})
    print(f"Data saved to {filename}")

if __name__ == "__main__":
    records = get_all_records()
    headers_mapping = get_header_mappings()
    save_records_to_csv(records, headers_mapping)
 

Userlevel 7
Badge +11

Wow! Awesome work here, @smccarthy956! 🙌

Thanks so much for following up here and sharing the code you used for this. I’m sure it will be super helpful to other folks in the Community looking to do the same! 🤗

You asked “If you can let me know if the records will be available in the ZAP process after the API call, I will greatly appreciated it. I have to assume so but I want to confirm.” By that, do you mean will the data for each record that’s found and output by the Code step into a CSV file then be available to select in the subsequent actions in the Zap?

If so, the answer would be no. In order to access it you’d need to import the CSV using a Formatter (Utilities > Import CSV File action). That should then give the Zap access to the individual record data contained within the CSV file. See Import CSV files into Zaps for more details.

Hope that helps. If I’ve misunderstood your question or you run into any issues on that just let us know! 🙂