Skip to content

TypeScript SDK - Set Client

The DBX TypeScript SDK provides a set client for working with Redis set data structures. This client offers type-safe methods for all set operations with full TypeScript support.

Installation

npm install @0dbx/redis

Basic Usage

REST Client

import { DBXClient } from "@effortlesslabs/dbx";
const client = new DBXClient({ baseUrl: "http://localhost:8080", token: "your-jwt-token" });
const setClient = client.set;

WebSocket Client

import { DBXWebSocketClient } from "@effortlesslabs/dbx";
const client = new DBXWebSocketClient({ url: "ws://localhost:8080/ws", token: "your-jwt-token" });
await client.connect();
const setClient = client.set;

Set Operations

SADD - Add Members

await setClient.sadd("users:online", ["user:123", "user:456"]);

SREM - Remove Members

await setClient.srem("users:online", ["user:123"]);

SMEMBERS - Get All Members

const members = await setClient.smembers("users:online");

SISMEMBER - Check Member Exists

const exists = await setClient.sismember("users:online", "user:123");

SCARD - Get Set Size

const size = await setClient.scard("users:online");

SPOP - Remove Random Member

const popped = await setClient.spop("users:online", 1);

SRANDMEMBER - Get Random Member

const randomMember = await setClient.srandmember("users:online", 1);

SMOVE - Move Member

const moved = await setClient.smove("users:online", "users:away", "user:123");

SINTER - Set Intersection

const intersection = await setClient.sinter(["users:online", "users:premium"]);

SUNION - Set Union

const union = await setClient.sunion(["users:online", "users:away"]);

SDIFF - Set Difference

const difference = await setClient.sdiff(["users:online", "users:premium"]);

SINTERSTORE/SUNIONSTORE/SDIFFSTORE - Store Results

const cardinality = await setClient.sinterstore("result", ["set1", "set2"]);

SSCAN - Scan Members

const { cursor, members } = await setClient.sscan("users:online", 0, {
  count: 10,
  match: "user:*",
});

Error Handling

All methods throw DBXError on failure. See String Client for error handling examples.

Best Practices

  • Use descriptive set names
  • Use batch operations for efficiency
  • Set TTL on set keys for temporary data
  • Use set partitioning for large datasets

Set Operations

The DBX TypeScript SDK provides comprehensive set operations with full TypeScript support and high-performance NAPI bindings.

Installation

npm install @0dbx/redis

Basic Usage

import { DbxRedisClient } from "@0dbx/redis";
 
// Create client
const client = new DbxRedisClient("http://localhost:3000");
 
// Set operations
await client.set.addMember("tags", "redis");
const members = await client.set.getMembers("tags");

WebSocket Client

import { DbxWsClient } from "@0dbx/redis";
 
// Create WebSocket client
const wsClient = new DbxWsClient("ws://localhost:3000/redis_ws");
 
// Set operations via WebSocket
await wsClient.set.addMember("tags", "redis");
const members = await wsClient.set.getMembers("tags");

Overview

Set operations in Redis allow you to work with unordered collections of unique strings. Sets are perfect for managing unique items, tags, and relationships.

Basic Operations

Creating a Set Client

import { DbxRedisClient } from "@0dbx/redis";
 
const client = new DbxRedisClient("http://localhost:3000");
const setClient = client.set;

Adding Members

// Add a single member to a set
await setClient.addMember("tags", "redis");
 
// Add multiple members to a set
await setClient.addMembers("tags", ["redis", "database", "nosql"]);
 
// Add with TTL (Time To Live) in seconds
await setClient.addMember("temp-set", "member1", 3600); // expires in 1 hour

Getting Members

// Get all members of a set
const members = await setClient.getMembers("tags");
console.log(members); // ["redis", "database", "nosql"]
 
// Get set cardinality (number of members)
const cardinality = await setClient.getCardinality("tags");
console.log(cardinality); // 3

Removing Members

// Remove a single member
await setClient.removeMember("tags", "nosql");
 
// Remove multiple members
await setClient.removeMembers("tags", ["database", "nosql"]);
 
// Check if removal was successful
const members = await setClient.getMembers("tags");
console.log(members); // ["redis"]

Checking Membership

// Check if a member exists in a set
const isMember = await setClient.isMember("tags", "redis");
console.log(isMember); // true
 
// Check multiple members
const memberStatus = await setClient.areMembers("tags", ["redis", "database"]);
console.log(memberStatus); // [true, false]

Advanced Operations

Set Operations

// Union of multiple sets
const union = await setClient.union(["set1", "set2", "set3"]);
 
// Intersection of multiple sets
const intersection = await setClient.intersection(["set1", "set2"]);
 
// Difference between sets (set1 - set2)
const difference = await setClient.difference("set1", "set2");
 
// Store union result in a new set
await setClient.unionStore("result-set", ["set1", "set2"]);
 
// Store intersection result in a new set
await setClient.intersectionStore("result-set", ["set1", "set2"]);

Random Operations

// Get a random member from a set
const randomMember = await setClient.getRandomMember("tags");
 
// Get multiple random members
const randomMembers = await setClient.getRandomMembers("tags", 3);
 
// Remove and return a random member
const poppedMember = await setClient.popMember("tags");

Set Information

// Get set cardinality
const size = await setClient.getCardinality("tags");
 
// Check if set exists
const exists = await setClient.exists("tags");
 
// Get TTL for a set
const ttl = await setClient.ttl("tags");
 
// Set TTL for a set
await setClient.expire("tags", 7200); // 2 hours

Batch Operations

// Perform multiple set operations in a single request
const results = await setClient.batch([
  { type: "addMember", key: "set1", member: "member1" },
  { type: "addMembers", key: "set2", members: ["member2", "member3"] },
  { type: "getMembers", key: "set3" },
  { type: "removeMember", key: "set1", member: "member1" },
]);
 
console.log(results);
// [
//   { success: true, added: 1 },
//   { success: true, added: 2 },
//   { members: ["existing", "members"] },
//   { success: true, removed: 1 }
// ]

WebSocket Set Operations

Creating a WebSocket Set Client

import { DbxWsClient } from "@0dbx/redis";
 
const wsClient = new DbxWsClient("ws://localhost:3000/redis_ws");
const wsSetClient = wsClient.set;

WebSocket Set Operations

// Add member via WebSocket
await wsSetClient.addMember("tags", "redis");
 
// Get members via WebSocket
const members = await wsSetClient.getMembers("tags");
 
// Remove member via WebSocket
await wsSetClient.removeMember("tags", "redis");
 
// Check membership via WebSocket
const isMember = await wsSetClient.isMember("tags", "redis");
 
// Set operations via WebSocket
const union = await wsSetClient.union(["set1", "set2"]);
const intersection = await wsSetClient.intersection(["set1", "set2"]);

Error Handling

Common Error Patterns

try {
  const members = await setClient.getMembers("non-existent-set");
} catch (error) {
  if (error.message.includes("not found")) {
    console.log("Set doesn't exist");
  } else if (error.message.includes("timeout")) {
    console.log("Request timed out");
  } else {
    console.error("Unexpected error:", error);
  }
}

Type-Safe Error Handling

interface SetOperationError {
  message: string;
  code?: string;
  status?: number;
}
 
async function safeSetOperation<T>(operation: () => Promise<T>): Promise<T | null> {
  try {
    return await operation();
  } catch (error) {
    const dbxError = error as SetOperationError;
 
    switch (dbxError.code) {
      case "not_found":
        console.warn("Set not found");
        return null;
      case "timeout":
        console.error("Operation timed out");
        return null;
      default:
        console.error("Set operation failed:", dbxError.message);
        return null;
    }
  }
}
 
// Usage
const members = await safeSetOperation(() => setClient.getMembers("my-set"));

Performance Optimization

Connection Reuse

// Create a singleton client for your application
class SetService {
  private static instance: DbxRedisClient;
  private static setClient: any;

  static getInstance(): any {
    if (!SetService.instance) {
      SetService.instance = new DbxRedisClient("http://localhost:3000");
      SetService.setClient = SetService.instance.set;
    }
    return SetService.setClient;
  }
}

// Use throughout your application
const setClient = SetService.getInstance();

Batch Operations for Performance

// Instead of multiple individual requests
const promises = [
  setClient.addMember("set1", "member1"),
  setClient.addMember("set1", "member2"),
  setClient.addMember("set1", "member3"),
];
await Promise.all(promises);
 
// Use batch operations for better performance
await setClient.batch([
  { type: "addMember", key: "set1", member: "member1" },
  { type: "addMember", key: "set1", member: "member2" },
  { type: "addMember", key: "set1", member: "member3" },
]);

Real-World Examples

Tag Management System

class TagManager {
  private client: any;
  private prefix = "tags:";
 
  constructor(client: any) {
    this.client = client;
  }
 
  async addTagsToItem(itemId: string, tags: string[]): Promise<void> {
    const key = `${this.prefix}item:${itemId}`;
    await this.client.addMembers(key, tags);
  }
 
  async removeTagsFromItem(itemId: string, tags: string[]): Promise<void> {
    const key = `${this.prefix}item:${itemId}`;
    await this.client.removeMembers(key, tags);
  }
 
  async getItemTags(itemId: string): Promise<string[]> {
    const key = `${this.prefix}item:${itemId}`;
    return await this.client.getMembers(key);
  }
 
  async findItemsWithTag(tag: string): Promise<string[]> {
    const key = `${this.prefix}tag:${tag}`;
    return await this.client.getMembers(key);
  }
 
  async getPopularTags(limit: number = 10): Promise<string[]> {
    // This would require additional implementation for popularity tracking
    const allTags = await this.client.getMembers("tags:popular");
    return allTags.slice(0, limit);
  }
}
 
// Usage
const tagManager = new TagManager(setClient);
await tagManager.addTagsToItem("post:123", ["redis", "database", "tutorial"]);
const tags = await tagManager.getItemTags("post:123");

User Following System

class FollowSystem {
  private client: any;
  private followingPrefix = "following:";
  private followersPrefix = "followers:";
 
  constructor(client: any) {
    this.client = client;
  }
 
  async followUser(followerId: string, targetId: string): Promise<void> {
    const followingKey = `${this.followingPrefix}${followerId}`;
    const followersKey = `${this.followersPrefix}${targetId}`;
 
    await Promise.all([
      this.client.addMember(followingKey, targetId),
      this.client.addMember(followersKey, followerId),
    ]);
  }
 
  async unfollowUser(followerId: string, targetId: string): Promise<void> {
    const followingKey = `${this.followingPrefix}${followerId}`;
    const followersKey = `${this.followersPrefix}${targetId}`;
 
    await Promise.all([
      this.client.removeMember(followingKey, targetId),
      this.client.removeMember(followersKey, followerId),
    ]);
  }
 
  async getFollowing(userId: string): Promise<string[]> {
    const key = `${this.followingPrefix}${userId}`;
    return await this.client.getMembers(key);
  }
 
  async getFollowers(userId: string): Promise<string[]> {
    const key = `${this.followersPrefix}${userId}`;
    return await this.client.getMembers(key);
  }
 
  async isFollowing(followerId: string, targetId: string): Promise<boolean> {
    const key = `${this.followingPrefix}${followerId}`;
    return await this.client.isMember(key, targetId);
  }
 
  async getMutualFollowers(user1Id: string, user2Id: string): Promise<string[]> {
    const followers1 = `${this.followersPrefix}${user1Id}`;
    const followers2 = `${this.followersPrefix}${user2Id}`;
 
    return await this.client.intersection([followers1, followers2]);
  }
}
 
// Usage
const followSystem = new FollowSystem(setClient);
await followSystem.followUser("user:123", "user:456");
const following = await followSystem.getFollowing("user:123");
const isFollowing = await followSystem.isFollowing("user:123", "user:456");

Online Users Tracking

class OnlineUsersTracker {
  private client: any;
  private onlineKey = "online:users";
  private sessionPrefix = "session:";
 
  constructor(client: any) {
    this.client = client;
  }
 
  async userOnline(userId: string, sessionId: string): Promise<void> {
    await Promise.all([
      this.client.addMember(this.onlineKey, userId),
      this.client.addMember(`${this.sessionPrefix}${userId}`, sessionId),
    ]);
  }
 
  async userOffline(userId: string): Promise<void> {
    await Promise.all([
      this.client.removeMember(this.onlineKey, userId),
      this.client.delete(`${this.sessionPrefix}${userId}`),
    ]);
  }
 
  async getOnlineUsers(): Promise<string[]> {
    return await this.client.getMembers(this.onlineKey);
  }
 
  async getOnlineCount(): Promise<number> {
    return await this.client.getCardinality(this.onlineKey);
  }
 
  async isUserOnline(userId: string): Promise<boolean> {
    return await this.client.isMember(this.onlineKey, userId);
  }
 
  async getUserSessions(userId: string): Promise<string[]> {
    return await this.client.getMembers(`${this.sessionPrefix}${userId}`);
  }
}
 
// Usage
const onlineTracker = new OnlineUsersTracker(setClient);
await onlineTracker.userOnline("user:123", "session:abc");
const onlineUsers = await onlineTracker.getOnlineUsers();
const onlineCount = await onlineTracker.getOnlineCount();

API Reference

Methods

MethodDescriptionParametersReturns
addMember(key, member, ttl?)Add a member to a setkey: string, member: string, ttl?: numberPromise<void>
addMembers(key, members, ttl?)Add multiple members to a setkey: string, members: string[], ttl?: numberPromise<void>
getMembers(key)Get all members of a setkey: stringPromise<string[]>
getCardinality(key)Get set cardinalitykey: stringPromise<number>
removeMember(key, member)Remove a member from a setkey: string, member: stringPromise<void>
removeMembers(key, members)Remove multiple members from a setkey: string, members: string[]Promise<void>
isMember(key, member)Check if member exists in setkey: string, member: stringPromise<boolean>
areMembers(key, members)Check if multiple members exist in setkey: string, members: string[]Promise<boolean[]>
union(keys)Get union of multiple setskeys: string[]Promise<string[]>
intersection(keys)Get intersection of multiple setskeys: string[]Promise<string[]>
difference(key1, key2)Get difference between two setskey1: string, key2: stringPromise<string[]>
getRandomMember(key)Get a random member from a setkey: stringPromise<string>
getRandomMembers(key, count)Get multiple random members from a setkey: string, count: numberPromise<string[]>
popMember(key)Remove and return a random memberkey: stringPromise<string>
exists(key)Check if set existskey: stringPromise<boolean>
ttl(key)Get remaining TTLkey: stringPromise<number>
expire(key, ttl)Set TTL for setkey: string, ttl: numberPromise<void>
batch(operations)Batch operationsoperations: Array<BatchOperation>Promise<Array<any>>

Batch Operation Types

interface BatchOperation {
  type:
    | "addMember"
    | "addMembers"
    | "getMembers"
    | "removeMember"
    | "removeMembers"
    | "isMember"
    | "union"
    | "intersection";
  key: string;
  member?: string;
  members?: string[];
  keys?: string[];
}

Next Steps