{"id":25774444,"url":"https://github.com/markusand/painless-airtable","last_synced_at":"2025-08-02T12:33:58.431Z","repository":{"id":57318267,"uuid":"383977569","full_name":"markusand/painless-airtable","owner":"markusand","description":"Easily interact with the Airtable API","archived":false,"fork":false,"pushed_at":"2025-05-07T16:41:12.000Z","size":339,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-06-03T09:19:39.966Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/markusand.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2021-07-08T02:22:25.000Z","updated_at":"2025-05-07T16:41:18.000Z","dependencies_parsed_at":"2025-06-02T21:14:36.240Z","dependency_job_id":"054ada02-a034-4055-b9ea-b2d7b948b3ac","html_url":"https://github.com/markusand/painless-airtable","commit_stats":{"total_commits":40,"total_committers":3,"mean_commits":"13.333333333333334","dds":"0.42500000000000004","last_synced_commit":"2bd51ebadeddc55f4176b908018052aecef6255d"},"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/markusand/painless-airtable","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusand%2Fpainless-airtable","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusand%2Fpainless-airtable/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusand%2Fpainless-airtable/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusand%2Fpainless-airtable/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/markusand","download_url":"https://codeload.github.com/markusand/painless-airtable/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/markusand%2Fpainless-airtable/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268389260,"owners_count":24242762,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-02-27T05:29:59.191Z","updated_at":"2025-08-02T12:33:58.421Z","avatar_url":"https://github.com/markusand.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Painless Airtable\n\nEasily interact with the Airtable API.\n\n[![version](https://img.shields.io/npm/v/painless-airtable)](https://npmjs.org/package/painless-airtable)\n[![size](https://img.shields.io/bundlephobia/minzip/painless-airtable)](https://bundlephobia.com/package/painless-airtable)\n![license](https://img.shields.io/npm/l/painless-airtable)\n\n## Usage\n\n```bash\nnpm install painless-airtable\n```\n\n```js\nimport { useAirtable } from 'painless-airtable';\n\nconst { AIRTABLE_TOKEN } = import.meta.env;\n\nconst airtable = useAirtable({\n  base: '\u003c\u003c Airtable base ID \u003e\u003e',\n  token: AIRTABLE_TOKEN,\n});\n\n// Queries return a promise and must be inside an async function\nconst results = await airtable.select('users', {\n  fields: ['name', 'phone', 'email'],\n  sort: { name: 'asc' },\n  max: 20,\n});\n```\n\n### Select \u0026 find records\n\nUse `select` method to retrieve all records that match certain conditions (if any), while `find` method will retrieve a single record by its Airtable's RECORD_ID.\n\n#### Options\n\nBoth methods accept some options to tailor the response from Airtable. If not provided the results will be as is with Airtable's default options.\n\n|option|type|default|description|\n|---|---|---|---|\n|base|string|undefined|Override the global base|\n|view|string|undefined|Get results from a specific view|\n|fields|array|undefined|Fields to retrieve|\n|max|int|undefined|Max number of results|\n|sort|object|undefined|Fields and order to sort the results|\n|persist|boolean|false|Automatically query for more results when max-results-per-query limit is reached. Be aware it may trigger the max-query-per-second limit error |\n|index|boolean|false|Return an an object of indexed records by RECORD_ID()|\n|where|object, string|undefined|Options to filter results|\n|expand|object|undefined|Options to expand linked records|\n|flatten|boolean|true|Flatten records, assigning metadata to underscore fields|\n\n#### Filter records with `where`\n\nResults may be filtered using an object parameter, with some *mongodb-like* operands.\n\n```js\nwhere: {\n  age: 35, // Field is equal to the value\n  age: [20, 25, 30], // Field is ANY of the values\n  age: { $lt: 35 },  // Apply an operand to the value\n  age: [20, { $gte: 50 }], // Combine options\n  is_valid: { checked: true },\n  tags: { has: 'development' },\n  type: { not: ['post', 'page'] },\n}\n```\n\n|operand|equivalent|meaning|\n|---|---|---|\n|is|=|Equal to|\n|has|⊃|Contains|\n|not|!|Negate|\n|checked||Is checked|\n||||\n|$eq|=|Equal to|\n|$neq|!=|Not equal to|\n|$lt|\u003c|Lower than|\n|$gt|\u003e|Greater than|\n|$lte|\u003c=|Lower than or equal|\n|$gte|\u003e=|Greater than or equal|\n\nFor more complex filtering you may have to write your own  [filterByFormula string](https://support.airtable.com/hc/en-us/articles/223247187-How-do-I-sort-filter-or-retrieve-ordered-records-in-the-API-) and pass it directly.\n\n#### Expand records\n\nAutomatically query and populate fields with linked records information.\n\u003e [!WARNING]\n\u003e Be aware it may trigger the max-query-per-second limit error.\n\n```js\nexpand: {\n  // Field with linked records to expand\n  company: {\n    // Linked table\n    table: 'companies',\n    // Accepts the same options object as the select method\n    options: { \n      fields: ['name', 'address', 'phone'],\n    },\n  },\n}\n```\n\n### Update records\n\nUse `update` method to update a record by passing a single record or an array (up to 10 limited by Airtable). Update records according to some other attribute than `_id` by using the `findBy` option. Use `typecast` option to force Airtable to infer the type of the field.\n\n## To Do\n\n- [ ] Add methods for a complete CRUD\n- [ ] Throttle queries (with retry option?)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusand%2Fpainless-airtable","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmarkusand%2Fpainless-airtable","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmarkusand%2Fpainless-airtable/lists"}