Jag kan inte knex i detalj och från en snabb sökning stöder knex för närvarande inte användningen av "limit" på uppdateringssatser så bara en beskrivning av det allmänna tillvägagångssättet.
Gör först en uppdatering för raden som matchar kriterierna och välj sedan den uppdaterade raden.
Så gör först en uppdateringsåtgärd som tilldelar det aktuella användar-id:t till den första obearbetade raden som antingen inte har någon användare tilldelad eller som redan har samma användare tilldelad:
update rows
set assignedTo = user.id
where assignedTo=0 or assignedTo=user.id
order by createdAt asc
limit 1
Jag tror att det kan fungera så här med knex med en rå fråga men har inte provat det:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid order by createdAt asc limit 1', {userid: user.id})
Detta kommer att leta efter den första (tidigaste skapadeAt) raden som är otilldelad eller redan tilldelad till samma användare och sedan tilldela den användaren. Detta händer på en gång.
Du kan sedan söka efter raden som tilldelats användaren:
const notProcessed = await knex('rows')
.select('*'')
.whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
.orderByRaw('createdAt asc')
.first();
Lägg märke till hur vi nu uttryckligen bara letar efter en rad som redan är tilldelad användaren.
Kombinerad
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();
Uppenbarligen behöver du inte markeringen om du inte vill arbeta med raden direkt.
Problemet är att när flera förfrågningar hanteras samtidigt måste du föreställa dig flera instanser av koden som körs samtidigt parallellt. Så med din ursprungliga kod kan två förfrågningar göra ditt val samtidigt innan någon av dem gör en uppdatering. Så båda kommer att få samma rad returnerad.
Genom att omedelbart uppdatera raden i satsen, även när två satser körs parallellt, ser databasen till att de inte ser samma rad.
Ett alternativt tillvägagångssätt för en lösning skulle vara att använda en mutex (som t.ex. async-mutex ) runt din ursprungliga kod för att se till att din ursprungliga val- och uppdateringsoperation är atomär (händer på en gång), men detta kommer med största sannolikhet att öka svarstiden för din applikation eftersom en förfrågningshanteringsoperation i vissa situationer måste vänta på en annan en för att fortsätta.