I have an interesting problem with Sequelize, the Node ORM library. I wish to insert this data into an empty table:
[
{ title: 'Expenditure 1', amount: 100 },
{ title: 'Expenditure 2', amount: 200 },
{ title: 'Expenditure 3', amount: 300 },
{ title: 'Expenditure 4', amount: 400 },
{ title: 'Expenditure 5', amount: 500 },
{ title: 'Expenditure 6', amount: 600 },
{ title: 'Expenditure 7', amount: 700 },
{ title: 'Expenditure 8', amount: 800 },
{ title: 'Expenditure 9', amount: 900 },
{ title: 'Expenditure 10', amount: 1000 },
{ title: 'Expenditure 11', amount: 1100 },
{ title: 'Expenditure 12', amount: 1200 },
{ title: 'Expenditure 13', amount: 1300 },
{ title: 'Expenditure 14', amount: 1400 },
{ title: 'Expenditure 15', amount: 1500 },
{ title: 'Expenditure 16', amount: 1600 },
{ title: 'Expenditure 17', amount: 1700 },
{ title: 'Expenditure 18', amount: 1800 },
{ title: 'Expenditure 19', amount: 1900 },
{ title: 'Expenditure 20', amount: 2000 }
]
As one would expect, in a fresh table, these will be given id
values of 1, 2, 3, etc in ascending order. So my first attempt to write these is thus:
const writeToTable = (model, rows) => {
let promises = rows.map((row) => model.create(row));
return Promise.all(promises);
}
OK, it sort of works, but the rows get inserted in an unpredictable order, since Promise.all
runs the promises in parallel, or at least does not guarantee to run them in order.
So I next tried this (using some code from this answer):
const writeToTable = (model, rows) => {
let promises = rows.map((row) => model.create(row));
let chain;
for (let i in promises) {
if (chain) chain = chain.then(() => promises[i]);
if (!chain) chain = promises[0];
}
return chain;
}
That looks like it must run the items in order, but no - running the code several times can produce different results. Odd!
So I next try this:
const writeToTable = async (model, rows) => {
let promises = rows.map((row) => model.create(row));
for (let promise of promises) {
await promise;
}
};
This is async, and has no return value, so should automatically return a Promise that resolves once all internal awaited calls are resolved. But, no - I still get occasionally wrongly ordered rows.
What technique could I use to ensure that my calls are executed in order? I suspect that Sequelize is doing some cacheing/late-writing here, and getting itself into a pickle. I am happy to hear of approaches in Sequelize that hand off a whole array to be inserted, but that feels a bit like cheating - I wonder if I would like to understand why this is failing.
I am absolutely sure the source array is correct.
It may help to know that these calls are being made in Jest to set up test data before calling a service and running assertions.