Description
Decrements the number stored at key by one. If the key does not exist, it is set to 0 before performing the operation. An error is returned if the key contains a value of the wrong type or contains a string that cannot be represented as an integer.
Syntax
redis.decr(key: string): Promise<number>
Parameters
The key containing the integer to decrement
Returns
The value of the key after the decrement
Examples
Basic Usage
import { Redis } from '@upstash/redis';
const redis = new Redis({
url: 'https://your-redis-url.upstash.io',
token: 'your-token'
});
// Set an initial value
await redis.set('counter', 10);
// Decrement by 1
const newValue = await redis.decr('counter');
console.log(newValue); // 9
const value = await redis.get('counter');
console.log(value); // "9"
Decrement Non-Existent Key
// Decrementing a non-existent key initializes it to 0 and then decrements
const result = await redis.decr('newcounter');
console.log(result); // -1
Multiple Decrements
await redis.set('inventory', 100);
// Decrement multiple times
await redis.decr('inventory'); // 99
await redis.decr('inventory'); // 98
await redis.decr('inventory'); // 97
const remaining = await redis.get('inventory');
console.log(remaining); // "97"
Inventory Management
// Track product inventory
async function sellProduct(productId: string, quantity: number = 1) {
for (let i = 0; i < quantity; i++) {
const remaining = await redis.decr(`product:${productId}:stock`);
if (remaining < 0) {
// Rollback - increment back
await redis.incr(`product:${productId}:stock`);
throw new Error('Out of stock');
}
}
}
// Initialize stock
await redis.set('product:123:stock', 5);
// Sell 2 items
await sellProduct('123', 2);
const stock = await redis.get('product:123:stock');
console.log(stock); // "3"
Countdown Timer
// Set up a countdown
await redis.set('countdown', 10);
const interval = setInterval(async () => {
const remaining = await redis.decr('countdown');
console.log(`${remaining} seconds remaining`);
if (remaining <= 0) {
clearInterval(interval);
console.log('Countdown complete!');
}
}, 1000);
Rate Limiting (Remaining Credits)
// Initialize user credits
await redis.set('user:123:credits', 100);
async function useCredit(userId: string): Promise<number> {
const remaining = await redis.decr(`user:${userId}:credits`);
if (remaining < 0) {
// Rollback and throw error
await redis.incr(`user:${userId}:credits`);
throw new Error('Insufficient credits');
}
return remaining;
}
try {
const credits = await useCredit('123');
console.log(`${credits} credits remaining`);
} catch (error) {
console.error(error.message);
}
Download Counter
// Track remaining downloads
async function trackDownload(fileId: string) {
const remaining = await redis.decr(`file:${fileId}:downloads:remaining`);
if (remaining < 0) {
await redis.incr(`file:${fileId}:downloads:remaining`);
return { allowed: false, remaining: 0 };
}
return { allowed: true, remaining };
}
// Set initial download limit
await redis.set('file:abc:downloads:remaining', 3);
const result1 = await trackDownload('abc');
console.log(result1); // { allowed: true, remaining: 2 }
const result2 = await trackDownload('abc');
console.log(result2); // { allowed: true, remaining: 1 }
Seat Reservation System
// Initialize available seats
await redis.set('event:concert:seats', 100);
async function reserveSeat(eventId: string): Promise<{ success: boolean; seatsLeft: number }> {
const seatsLeft = await redis.decr(`event:${eventId}:seats`);
if (seatsLeft < 0) {
// No seats available, rollback
await redis.incr(`event:${eventId}:seats`);
return { success: false, seatsLeft: 0 };
}
return { success: true, seatsLeft };
}
const reservation = await reserveSeat('concert');
if (reservation.success) {
console.log(`Seat reserved! ${reservation.seatsLeft} seats remaining`);
} else {
console.log('Sorry, event is sold out');
}
Notes
- This is an atomic operation, making it safe for concurrent decrements
- The value must be an integer or a string that can be parsed as an integer
- If the key contains a non-integer value, an error will be returned
- The operation has O(1) time complexity
- The range of values is limited to 64-bit signed integers
- Decrementing below zero is allowed (will result in negative numbers)
Error Handling
try {
// This will throw an error because "hello" is not a valid integer
await redis.set('mykey', 'hello');
await redis.decr('mykey');
} catch (error) {
console.error('Cannot decrement non-integer value');
}
- incr - Increment the integer value of a key by one
Redis Documentation
For more information, see the Redis DECR documentation.