我收到一个对象bigListFromClient
,其中包含任意数量的对象,每个对象可以具有任意数量的子代。每个对象都需要输入到我的数据库中,但是数据库需要为每个对象分配一个唯一的ID,子对象在发送给数据库之前必须具有其父对象的唯一ID。
我想创建某种Promise或其他调用结构,这些结构将异步调用自己,直到到达bigListFromClient
中的最后一个对象为止,但是我在弄清楚如何编写它上遇到了麻烦。
for(let i = 0; i < bigListFromClient.length; i++){
makeDbCallAsPromise(bigListFromClient[i].queryString, console.log); //I'm not just accepting anything from a user here, but how I get my queryString is kind of out of scope for this question
for(let j = 0; j < bigListFromClient[i].children.length; j++){
//the line below obviously doesn't work, I'm trying to figure out how to do this with something other than a for loop
makeDbCallAsPromise(bigListFromClient[i].children[j].queryString + [the uniqueID from the DB to insert this correctly as a child], console.log);
}
}
//this promise works great
makeDbCallAsPromise = function(queryString){
return new Promise((resolve, reject) => {
connection = mysql.createConnection(connectionCredentials);
connection.connect();
query = queryString;
connection.query(query, function (err, rows, fields) {
if (!err) {
resolve(rows);
} else {
console.log('Error while performing Query.');
console.log(err.code);
console.log(err.message);
reject(err);
}
});
connection.end();
})
};
我自己解决这个问题的尝试非常尴尬,以至于向您描述它们都是可怕的。
虽然我可以将所有创建孩子的电话推迟到在数据库中创建父母之前,但我想知道我所描述的方法是否可行。
答案 0 :(得分:1)
基本上有两种方法可以做到这一点。一种是顺序进行数据库调用,另一种是并行进行调用。
Javascript具有一个名为Promise.all
的并行内置函数,您向它传递了一个Promise
实例数组,并返回一个包含该数组的Promise
实例。
在您的情况下,您的代码应如下所示:
const result = Promise.all(
bigListFromClient.map(item =>
makeDbCallAsPromise(item.queryString).then(result =>
Promise.all(
item.children.map(item =>
makeDbCallAsPromise(item.queryString + [result.someId])
)
)
])
})
result
现在将包含一个解析为数组数组的Promise
。这些数组包含插入子级的结果。
使用更现代的方法(使用async
await
),按顺序进行操作,并将所有结果组合成一个平面数组:
const result = await bigListFromClient.reduce(
async (previous, item) => {
const previousResults = await previous
const result = await makeDbCallAsPromise(item.queryString)
const childResults = await item.children.reduce(
async (result, item) =>
[...(await result), await makeDbCallAsPromise(item.queryString + [result.someId])],
[]
)
return [...previousResults, result, ...childResults)
]),
[]
})
根据要实现的目标以及要如何构造代码,可以从不同的方法中进行选择。
答案 1 :(得分:0)
对于这种操作,请尝试查看bulk inserting。如果您打算在每次迭代中执行一次数据库查询/事务,请在每个父级上递归循环和/或对每个子级执行相同的过程。
const dbCall = async (elm) => {
elm.id = Math.random().toString(36).substring(7)
if (elm.children) {
await Promise.all(elm.children.map(child => {
child.parentId = elm.id
return dbCall(child)
}))
}
return elm
}
const elms = [
{
queryString: '',
children: [
{
queryString: ''
}
]
}
]
Promise.all(elms.map(dbCall)).then(elm => /* ... */)