Не познавам knex в детайли и от едно бързо търсене, knex в момента не поддържа използването на "limit" за изявления за актуализиране, така че само описание на общия подход.
Първо направете актуализация за реда, отговарящ на критериите, след което изберете този актуализиран ред.
И така, първо направете операция за актуализиране, която присвоява текущия потребителски идентификатор на първия необработен ред, който или няма назначен потребител, или вече има назначен същия потребител:
update rows
set assignedTo = user.id
where assignedTo=0 or assignedTo=user.id
order by createdAt asc
limit 1
Мисля, че може да работи по този начин с knex, използвайки необработена заявка, но не съм пробвал това:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
Това ще търси първия (най-ранно създаден в) ред, който не е присвоен или вече е присвоен на същия потребител, и след това ще присвои този потребител. Това се случва наведнъж.
След това можете да търсите реда, присвоен на потребителя:
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Забележете как сега изрично търсим само ред, който вече е присвоен на потребителя.
Комбиниран
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Очевидно не се нуждаете от избора, ако не искате да работите с реда незабавно.
Проблемът е, че когато няколко заявки се обработват едновременно, трябва да си представите, че няколко екземпляра на кода работят едновременно паралелно. Така че, с вашия оригинален код, две заявки могат да направят вашия избор едновременно, преди някоя от тях да направи актуализация. Така че и на двамата ще бъде върнат един и същ ред.
Чрез незабавно актуализиране на реда в израза, дори когато два оператора се изпълняват паралелно, базата данни ще се увери, че те не виждат един и същ ред.
Алтернативен подход за решение би бил използването на мютекс (като напр. async-mutex ) около оригиналния ви код, за да се уверите, че оригиналната ви операция за избор и актуализиране е атомарна (се случва наведнъж), но това най-вероятно ще увеличи времето за реакция на вашето приложение, защото в някои ситуации една операция за обработка на заявка ще трябва да изчака друга едно за продължаване.