首先,让我从我想要实现的开始。我想在 Airtable 中查询一个包含来自链接表的数据的表。Airtable 返回链接表中记录的 ID,所以我需要对这些记录中的每一个进行第二次查找以获取我想要的数据 (例如Name
)。最终,我想返回给客户端的 ID和的其他字段无法从链接的 API 实现
到目前为止,我能做的最好的事情就是在他们的 API 的done()
回调中执行一些代码。问题是这是不可扩展的,因为这意味着我会让自己进入回调地狱。(至少,这是我认为我已经能够确定的。)
这是我的代码(仅供参考,这是在 Azure 函数中运行的代码):
var Airtable = require("airtable");
var airtableApiKey = process.env.airtableApiKey;
module.exports = function (context, req) {
context.log('JavaScript HTTP trigger function processed a request.');
var base = new Airtable({
apiKey: airtableApiKey
}).base('appBASEID');
var resultObj;
var accumulator = [];
base('Products').select({
sort: [{
field: 'Identifier',
direction: 'asc'
}]
}).eachPage(function page(records, fetchNextPage) {
records.forEach(function (record) {
context.log('Retrieved ', record.get('Identifier'));
context.log('Retrieved ', record.get('Vendor'));
accumulator.push(record._rawJson);
// base('Vendors').find(record.get('Vendor')[0], function( err, record) {
// if (err) { context.error(err); return; }
// context.log(record.get('Name'));
// });
});
fetchNextPage();
}, function done(error) {
context.res = {
// status: 200, /* Defaults to 200 */
body: JSON.p(JSON.stringify(accumulator))
};
context.done();
});
};
您可以看到我在.eachPage()
部分中注释了一些行,因为正如我在处理此问题时了解到的那样,该代码没有按照我预期的顺序执行。
如何foreach
通过accumulator
和.find()
我需要的记录?
4
看起来您遇到的问题是done
回调在forEach
中的find
调用可以完成之前执行。forEach
可能会阻塞,但是每个find
调用都不会。因此,您可以继续获取更多页面,并最终获取所有页面,在之前,您已经成功提取了所有链接记录
这里是我写的代码来管理这个。请注意,它很长,有可能的改进空间。我试图也照顾的情况下,你的链接字段可能有多个元素,你可能有多个链接字段列,你有兴趣查找。
var base = Airtable.base(base_id)
var table = base.table(table_name);
// create a map between the linked record columns in your table
// and the table that those linked record's point to
var linked_fields = {
'Local Column A': 'Foreign Table X',
'Local Column B': 'Foreign Table Y'
}
// manage all records and promises
var all_records = [];
var all_promises = [];
// cycle through all pages in our table
table.select().eachPage(function page(records, fetchNextPage) {
// for each record, go through each linked field and pull all associated linked records
var page = records.map((record) => {
// for each column, we want to check if the given record has any linked records
// if it does, then go ahead and perform a fetch in the foreign table
// linked record fields are a list because there can be multiple linked records
// so we have to loop through each ID
var record_promises = Object.keys(linked_fields).map((field) => {
if (record.fields[field] !== undefined) {
let t = base.table(linked_fields[field]);
var linked_promises = record.fields[field].map((foreign_record_id) => {
return t.find(foreign_record_id);
});
// wait for this record to get all of its linked fields
return Promise.all(linked_promises).then((values) => {
// for each linked field, we don't need all the extra Airtable SDK noise
// so just use the rawJSON structure from the foreign record
// but update both the rawJson and fields structures in the local record
values = values.map((v) => {
return v._rawJson;
});
record.fields[field] = values;
record._rawJson.fields[field] = values;
});
}
});
// wait for the record to finish updating all linked fields
// and then return the record
return Promise.all(record_promises).then(() => {
return record;
});
});
// we have to wait for all records in this page to get updated information
// we can use all_promises to track all of our active promises
all_promises.push(Promise.all(page));
// we don't need to wait for everything to resolve before fetching the next page
// and we probably don't want to wait.
// Airtable pagination will die if you wait too long in between calls
// and you have to start all over
fetchNextPage();
}, function done(error) {
if (error) {
reject(error);
}
// once we've fetched all pages, wait for all those pages to settle
// we will get a list of lists at the end of this, where each page is a different list
// so we can now flatten it into a single list by pushing all records into all_records
Promise.all(all_promises).then((results) => {
for (var i in results) {
all_records.push.apply(all_records, results[i]);
}
context.res = {
// status: 200, /* Defaults to 200 */
body: JSON.p(JSON.stringify(all_records))
};
context.done();
}).catch((err) => {
// handle error response
});
});
本站系公益性非盈利分享网址,本文来自用户投稿,不代表码文网立场,如若转载,请注明出处
评论列表(59条)