0

I receive an object bigListFromClient that includes an arbitrary number of objects each of which may have an arbitrary number of children. Every object needs to be entered into my database, but the DB needs to assign each of them a unique ID and child objects need to have the unique ID of their parents attached to them before they are sent off to the DB.

I want to create some sort of Promise or other calling structure that would call itself asynchronously until it reached the last object in bigListFromClient but I'm having trouble figuring out how to write it.

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();
    })
};

My attempts at solving this on my own are so embarrassingly bad that even describing them to you would be awful.

While I could defer all the calls to creating children until the parents have been created in the DB, I wonder if the approach I've described is possible.

Glen Pierce
  • 4,401
  • 5
  • 31
  • 50

2 Answers2

1

There are essentially two ways to do this. One is making the database calls sequential and the other one is making the calls parallel.

Javascript has a built-in function for parallel called Promise.all, you pass it an array of Promise instances and it returns a Promise instance containing the array.

In your case your code would look like this:

const result = Promise.all(
  bigListFromClient.map(item => 
    makeDbCallAsPromise(item.queryString).then(result =>
      Promise.all(
        item.children.map(item => 
          makeDbCallAsPromise(item.queryString + [result.someId])
        )
      )
    ])
  })

result will now contain a Promise that resolves to an array of arrays. These arrays contain the result of intserting children.

Using a more modern approach (with async await), sequential and with all results in a flat array:

 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)
  ]),
  []
})

Depending on what you want to achieve and how you want to structure your code you can pick and choose from the different approaches.

EECOLOR
  • 11,184
  • 3
  • 41
  • 75
0

For this sort of operation, try looking into bulk inserting. If you are intent on performing a single DB query/transaction per iteration, loop recursively over each parent and/or execute the same procedure for each child.

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 => /* ... */)
dcd018
  • 711
  • 5
  • 13