Redis sets

Introduction to Redis sets

A Redis set is an unordered collection of unique strings (members). You can use Redis sets to efficiently:

  • Track unique items (e.g., track all unique IP addresses accessing a given blog post).
  • Represent relations (e.g., the set of all users with a given role).
  • Perform common set operations such as intersection, unions, and differences.

Examples

  • Store the sets of bikes racing in France and the USA. Note that if you add a member that already exists, it will be ignored.

    Foundational: Add members to a set using SADD when you need to store unique items (duplicates are silently ignored)
    > SADD bikes:racing:france bike:1
    (integer) 1
    > SADD bikes:racing:france bike:1
    (integer) 0
    > SADD bikes:racing:france bike:2 bike:3
    (integer) 2
    > SADD bikes:racing:usa bike:1 bike:4
    (integer) 2
    res1 = r.sadd("bikes:racing:france", "bike:1")
    print(res1)  # >>> 1
    
    res2 = r.sadd("bikes:racing:france", "bike:1")
    print(res2)  # >>> 0
    
    res3 = r.sadd("bikes:racing:france", "bike:2", "bike:3")
    print(res3)  # >>> 2
    
    res4 = r.sadd("bikes:racing:usa", "bike:1", "bike:4")
    print(res4)  # >>> 2
    
    const res1 = await client.sAdd('bikes:racing:france', 'bike:1')
    console.log(res1)  // >>> 1
    
    const res2 = await client.sAdd('bikes:racing:france', 'bike:1')
    console.log(res2)  // >>> 0
    const res3 = await client.sAdd('bikes:racing:france', ['bike:2', 'bike:3'])
    console.log(res3)  // >>> 2
    const res4 = await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    console.log(res4)  // >>> 2
    
            long res1 = jedis.sadd("bikes:racing:france", "bike:1");
            System.out.println(res1);  // >>> 1
    
            long res2 = jedis.sadd("bikes:racing:france", "bike:1");
            System.out.println(res2);  // >>> 0
    
            long res3 = jedis.sadd("bikes:racing:france", "bike:2", "bike:3");
            System.out.println(res3);  // >>> 2
    
            long res4 = jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
            System.out.println(res4);  // >>> 2
    
                CompletableFuture<Void> sAdd = asyncCommands.sadd("bikes:racing:france", "bike:1").thenCompose(res1 -> {
                    System.out.println(res1); // >>> 1
    
                    return asyncCommands.sadd("bikes:racing:france", "bike:1");
                }).thenCompose(res2 -> {
                    System.out.println(res2); // >>> 0
    
                    return asyncCommands.sadd("bikes:racing:france", "bike:2", "bike:3");
                }).thenCompose(res3 -> {
                    System.out.println(res3); // >>> 2
    
                    return asyncCommands.sadd("bikes:racing:usa", "bike:1", "bike:4");
                })
                        .thenAccept(System.out::println)
                        // >>> 2
                        .toCompletableFuture();
    
                Mono<Void> sAdd = reactiveCommands.sadd("bikes:racing:france", "bike:1").doOnNext(result -> {
                    System.out.println(result); // >>> 1
                }).flatMap(v -> reactiveCommands.sadd("bikes:racing:france", "bike:1")).doOnNext(result -> {
                    System.out.println(result); // >>> 0
                }).flatMap(v -> reactiveCommands.sadd("bikes:racing:france", "bike:2", "bike:3")).doOnNext(result -> {
                    System.out.println(result); // >>> 2
                }).flatMap(v -> reactiveCommands.sadd("bikes:racing:usa", "bike:1", "bike:4")).doOnNext(result -> {
                    System.out.println(result); // >>> 2
                }).then();
    
    	res1, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res1) // >>> 1
    
    	res2, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res2) // >>> 0
    
    	res3, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:2", "bike:3").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res3) // >>> 2
    
    	res4, err := rdb.SAdd(ctx, "bikes:racing:usa", "bike:1", "bike:4").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res4) // >>> 2
    
            long res1 = db.SetAdd("bikes:racing:france", ["bike:1"]);
            Console.WriteLine(res1);    // >>> 1
    
            long res2 = db.SetAdd("bikes:racing:france", ["bike:1"]);
            Console.WriteLine(res2);    // >>> 0
    
            long res3 = db.SetAdd("bikes:racing:france", ["bike:2", "bike:3"]);
            Console.WriteLine(res3);    // >>> 2
    
            long res4 = db.SetAdd("bikes:racing:usa", ["bike:1", "bike:4"]);
            Console.WriteLine(res4);    // >>> 2
    
            $res1 = $r->sadd('bikes:racing:france', ['bike:1']);
            echo $res1 . PHP_EOL;
            // >>> 1
    
            $res2 = $r->sadd('bikes:racing:france', ['bike:1']);
            echo $res2 . PHP_EOL;
            // >>> 0
    
            $res3 = $r->sadd('bikes:racing:france', ['bike:2', 'bike:3']);
            echo $res3 . PHP_EOL;
            // >>> 2
    
            $res4 = $r->sadd('bikes:racing:usa', ['bike:1', 'bike:4']);
            echo $res4 . PHP_EOL;
            // >>> 2
    
    res1 = r.sadd('bikes:racing:france', ['bike:1'])
    puts res1 # 1
    
    res2 = r.sadd('bikes:racing:france', ['bike:1'])
    puts res2 # 0
    
    res3 = r.sadd('bikes:racing:france', ['bike:2', 'bike:3'])
    puts res3 # 2
    
    res4 = r.sadd('bikes:racing:usa', ['bike:1', 'bike:4'])
    puts res4 # 2
    
            if let Ok(res) = r.sadd("bikes:racing:france", "bike:1") {
                let res: usize = res;
                println!("{res}"); // >>> 1
            }
    
            if let Ok(res) = r.sadd("bikes:racing:france", "bike:1") {
                let res: usize = res;
                println!("{res}"); // >>> 0
            }
    
            if let Ok(res) = r.sadd("bikes:racing:france", &["bike:2", "bike:3"]) {
                let res: usize = res;
                println!("{res}"); // >>> 2
            }
    
            if let Ok(res) = r.sadd("bikes:racing:usa", &["bike:1", "bike:4"]) {
                let res: usize = res;
                println!("{res}"); // >>> 2
            }
    
            if let Ok(res) = r.sadd("bikes:racing:france", "bike:1").await {
                let res: usize = res;
                println!("{res}"); // >>> 1
            }
    
            if let Ok(res) = r.sadd("bikes:racing:france", "bike:1").await {
                let res: usize = res;
                println!("{res}"); // >>> 0
            }
    
            if let Ok(res) = r.sadd("bikes:racing:france", &["bike:2", "bike:3"]).await {
                let res: usize = res;
                println!("{res}"); // >>> 2
            }
    
            if let Ok(res) = r.sadd("bikes:racing:usa", &["bike:1", "bike:4"]).await {
                let res: usize = res;
                println!("{res}"); // >>> 2
            }
    

  • Check whether bike:1 or bike:2 are racing in the US.

    Foundational: Test set membership using SISMEMBER when you need O(1) lookups (much faster than checking a list)
    > SISMEMBER bikes:racing:usa bike:1
    (integer) 1
    > SISMEMBER bikes:racing:usa bike:2
    (integer) 0
    r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
    r.sadd("bikes:racing:usa", "bike:1", "bike:4")
    res5 = r.sismember("bikes:racing:usa", "bike:1")
    print(res5)  # >>> 1
    
    res6 = r.sismember("bikes:racing:usa", "bike:2")
    print(res6)  # >>> 0
    
    await client.del('bikes:racing:france')
    await client.del('bikes:racing:usa')
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    const res5 = await client.sIsMember('bikes:racing:usa', 'bike:1')
    console.log(res5)  // >>> 1
    
    const res6 = await client.sIsMember('bikes:racing:usa', 'bike:2')
    console.log(res6)  // >>> 0
    
            jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
            jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
    
            boolean res5 = jedis.sismember("bikes:racing:usa", "bike:1");
            System.out.println(res5);  // >>> true
    
            boolean res6 = jedis.sismember("bikes:racing:usa", "bike:2");
            System.out.println(res6);  // >>> false
    
                CompletableFuture<Void> sIsMember = sAdd.thenCompose(r -> {
                    return asyncCommands.sismember("bikes:racing:usa", "bike:1");
                }).thenCompose(res4 -> {
                    System.out.println(res4); // >>> true
    
                    return asyncCommands.sismember("bikes:racing:usa", "bike:2");
                })
                        .thenAccept(System.out::println) // >>> false
                        .toCompletableFuture();
    
                Mono<Boolean> sIsMember1 = reactiveCommands.sismember("bikes:racing:usa", "bike:1").doOnNext(result -> {
                    System.out.println(result); // >>> true
                });
    
                Mono<Boolean> sIsMember2 = reactiveCommands.sismember("bikes:racing:usa", "bike:2").doOnNext(result -> {
                    System.out.println(result); // >>> false
                });
    
    	res5, err := rdb.SIsMember(ctx, "bikes:racing:usa", "bike:1").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res5) // >>> true
    
    	res6, err := rdb.SIsMember(ctx, "bikes:racing:usa", "bike:2").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res6) // >>> false
    
            bool res5 = db.SetContains("bikes:racing:france", "bike:1");
            Console.WriteLine(res5);    // >>> True
    
            bool res6 = db.SetContains("bikes:racing:usa", "bike:2");
            Console.WriteLine(res6);    // >>> False
    
            $res5 = $r->sismember('bikes:racing:usa', 'bike:1');
            echo $res5 . PHP_EOL;
            // >>> 1
    
            $res6 = $r->sismember('bikes:racing:usa', 'bike:2');
            echo $res6 . PHP_EOL;
            // >>> 0
    
    r.del('bikes:racing:france', 'bikes:racing:usa')
    r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    r.sadd('bikes:racing:usa', ['bike:1', 'bike:4'])
    res5 = r.sismember('bikes:racing:usa', 'bike:1')
    puts res5 # true
    
    res6 = r.sismember('bikes:racing:usa', 'bike:2')
    puts res6 # false
    
            if let Ok(res) = r.sismember("bikes:racing:usa", "bike:1") {
                let res: bool = res;
                println!("{}", i32::from(res)); // >>> 1
            }
    
            if let Ok(res) = r.sismember("bikes:racing:usa", "bike:2") {
                let res: bool = res;
                println!("{}", i32::from(res)); // >>> 0
            }
    
            if let Ok(res) = r.sismember("bikes:racing:usa", "bike:1").await {
                let res: bool = res;
                println!("{}", i32::from(res)); // >>> 1
            }
    
            if let Ok(res) = r.sismember("bikes:racing:usa", "bike:2").await {
                let res: bool = res;
                println!("{}", i32::from(res)); // >>> 0
            }
    

  • Which bikes are competing in both races?

    Set intersection: Find common members across multiple sets using SINTER when you need to identify shared items (e.g., users in multiple groups)
    > SINTER bikes:racing:france bikes:racing:usa
    1) "bike:1"
    r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
    r.sadd("bikes:racing:usa", "bike:1", "bike:4")
    res7 = r.sinter("bikes:racing:france", "bikes:racing:usa")
    print(res7)  # >>> {'bike:1'}
    
    import { createClient } from 'redis';
    
    const client = createClient();
    await client.connect();
    
    const res1 = await client.sAdd('bikes:racing:france', 'bike:1')
    console.log(res1)  // >>> 1
    
    const res2 = await client.sAdd('bikes:racing:france', 'bike:1')
    console.log(res2)  // >>> 0
    const res3 = await client.sAdd('bikes:racing:france', ['bike:2', 'bike:3'])
    console.log(res3)  // >>> 2
    const res4 = await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    console.log(res4)  // >>> 2
    
    
    await client.del('bikes:racing:france')
    await client.del('bikes:racing:usa')
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    const res5 = await client.sIsMember('bikes:racing:usa', 'bike:1')
    console.log(res5)  // >>> 1
    
    const res6 = await client.sIsMember('bikes:racing:usa', 'bike:2')
    console.log(res6)  // >>> 0
    
    
    await client.del('bikes:racing:france')
    await client.del('bikes:racing:usa')
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    const res7 = await client.sInter(['bikes:racing:france', 'bikes:racing:usa'])
    console.log(res7)  // >>> {'bike:1'}
    
    
    await client.del('bikes:racing:france')
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    const res8 = await client.sCard('bikes:racing:france')
    console.log(res8)  // >>> 3
    
    
    await client.del('bikes:racing:france')
    
    const res9 = await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    console.log(res9)  // >>> 3
    
    const res10 = await client.sMembers('bikes:racing:france')
    console.log(res10)  // >>> ['bike:1', 'bike:2', 'bike:3']
    
    
    const res11 = await client.sIsMember('bikes:racing:france', 'bike:1')
    console.log(res11)  // >>> 1
    
    const res12 = await client.smIsMember('bikes:racing:france', ['bike:2', 'bike:3', 'bike:4'])
    console.log(res12)  // >>> [1, 1, 0]
    
    
    await client.del('bikes:racing:france')
    await client.del('bikes:racing:usa')
    
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    const res13 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
    console.log(res13)  // >>> [ 'bike:2', 'bike:3' ]
    
    
    await client.del('bikes:racing:france')
    await client.del('bikes:racing:usa')
    await client.del('bikes:racing:italy')
    
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
    await client.sAdd('bikes:racing:italy', ['bike:1', 'bike:2', 'bike:3', 'bike:4'])
    
    const res14 = await client.sInter(
      ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
    )
    console.log(res14)  // >>> ['bike:1']
    
    const res15 = await client.sUnion(
      ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
    )
    console.log(res15)  // >>> ['bike:1', 'bike:2', 'bike:3', 'bike:4']
    
    const res16 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy'])
    console.log(res16)  // >>> []
    
    const res17 = await client.sDiff(['bikes:racing:usa', 'bikes:racing:france'])
    console.log(res17)  // >>> ['bike:4']
    
    const res18 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
    console.log(res18)  // >>> ['bike:2', 'bike:3']
    
    
    await client.del('bikes:racing:france')
    
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5'])
    
    const res19 = await client.sRem('bikes:racing:france', 'bike:1')
    console.log(res19)  // >>> 1
    
    const res20 = await client.sPop('bikes:racing:france')
    console.log(res20)  // >>> bike:3 or other random value
    
    const res21 = await client.sMembers('bikes:racing:france')
    console.log(res21)  // >>> ['bike:2', 'bike:4', 'bike:5']; depends on previous result
    
    const res22 = await client.sRandMember('bikes:racing:france')
    console.log(res22)  // >>> bike:4 or other random value
    
    
            jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
            jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
    
            Set<String> res7 = jedis.sinter("bikes:racing:france", "bikes:racing:usa");
            System.out.println(res7);  // >>> [bike:1]
    
                CompletableFuture<Void> sInter = sIsMember.thenCompose(r -> {
                    return asyncCommands.sinter("bikes:racing:france", "bikes:racing:usa");
                })
                        .thenAccept(System.out::println) // >>> ["bike:1"]
                        .toCompletableFuture();
    
                Mono<List<String>> sInter = reactiveCommands.sinter("bikes:racing:france", "bikes:racing:usa").collectList()
                        .doOnNext(result -> {
                            System.out.println(result); // >>> [bike:1]
                        });
    
    	res7, err := rdb.SInter(ctx, "bikes:racing:france", "bikes:racing:usa").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res7) // >>> [bike:1]
    
            long res7 = db.SetAdd("{bikes:racing}:france", ["bike:1", "bike:2", "bike:3"]);
            long res8 = db.SetAdd("{bikes:racing}:usa", ["bike:1", "bike:4"]);
    
            RedisValue[] res9 = db.SetCombine(SetOperation.Intersect, ["{bikes:racing}:france", "{bikes:racing}:usa"]);
            Console.WriteLine(string.Join(", ", res9)); // >>> bike:1
    
            $res7 = $r->sinter(['bikes:racing:france', 'bikes:racing:usa']);
            echo json_encode($res7) . PHP_EOL;
            // >>> ["bike:1"]
    
    r.del('bikes:racing:france', 'bikes:racing:usa')
    r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    r.sadd('bikes:racing:usa', ['bike:1', 'bike:4'])
    res7 = r.sinter('bikes:racing:france', 'bikes:racing:usa')
    puts res7.inspect # ["bike:1"]
    
            if let Ok(res) = r.sinter(&["bikes:racing:france", "bikes:racing:usa"]) {
                let res: HashSet<String> = res;
                let res = sorted_set(res);
                println!("{res:?}"); // >>> ["bike:1"]
            }
    
            if let Ok(res) = r.sinter(&["bikes:racing:france", "bikes:racing:usa"]).await {
                let res: HashSet<String> = res;
                let res = sorted_set(res);
                println!("{res:?}"); // >>> ["bike:1"]
            }
    

  • How many bikes are racing in France?

    Foundational: Get the cardinality of a set using SCARD when you need to count unique items efficiently
    > SCARD bikes:racing:france
    (integer) 3
    r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
    res8 = r.scard("bikes:racing:france")
    print(res8)  # >>> 3
    
    await client.del('bikes:racing:france')
    await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    const res8 = await client.sCard('bikes:racing:france')
    console.log(res8)  // >>> 3
    
            jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
    
            long res8 = jedis.scard("bikes:racing:france");
            System.out.println(res8);  // >>> 3
    
                CompletableFuture<Void> sCard = sInter.thenCompose(r -> {
                    return asyncCommands.scard("bikes:racing:france");
                })
                        .thenAccept(System.out::println) // >>> 3
                        .toCompletableFuture();
    
                Mono<Long> sCard = reactiveCommands.scard("bikes:racing:france").doOnNext(result -> {
                    System.out.println(result); // >>> 3
                });
    
    	res8, err := rdb.SCard(ctx, "bikes:racing:france").Result()
    
    	if err != nil {
    		panic(err)
    	}
    
    	fmt.Println(res8) // >>> 3
    
            long res10 = db.SetAdd("bikes:racing:france", ["bike:1", "bike:2", "bike:3"]);
            long res11 = db.SetLength("bikes:racing:france");
            Console.WriteLine(res11);   // >>> 3
    
            $res8 = $r->scard('bikes:racing:france');
            echo $res8 . PHP_EOL;
            // >>> 3
    
    r.del('bikes:racing:france')
    r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
    res8 = r.scard('bikes:racing:france')
    puts res8 # 3
    
            if let Ok(res) = r.scard("bikes:racing:france") {
                let res: usize = res;
                println!("{res}"); // >>> 3
            }
    
            if let Ok(res) = r.scard("bikes:racing:france").await {
                let res: usize = res;
                println!("{res}"); // >>> 3
            }
    

Tutorial

The SADD command adds new elements to a set. It's also possible to do a number of other operations against sets like testing if a given element already exists, performing the intersection, union or difference between multiple sets, and so forth.

Foundational: Retrieve all members from a set using SMEMBERS when you need the complete set (note: order is not guaranteed)
> DEL bikes:racing:france
(integer) 1
> SADD bikes:racing:france bike:1 bike:2 bike:3
(integer) 3
> SMEMBERS bikes:racing:france
1) bike:3
2) bike:1
3) bike:2
r.delete("bikes:racing:france")

res9 = r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
print(res9)  # >>> 3

res10 = r.smembers("bikes:racing:france")
print(res10)  # >>> {'bike:1', 'bike:2', 'bike:3'}
await client.del('bikes:racing:france')

const res9 = await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
console.log(res9)  // >>> 3

const res10 = await client.sMembers('bikes:racing:france')
console.log(res10)  // >>> ['bike:1', 'bike:2', 'bike:3']
        jedis.del("bikes:racing:france");

        long res9 = jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        System.out.println(res9);  // >>> 3

        Set<String> res10 = jedis.smembers("bikes:racing:france");
        System.out.println(res10);  // >>> [bike:1, bike:2, bike:3]
            CompletableFuture<Void> sAddSMembers = sCard.thenCompose(r -> {
                return asyncCommands.del("bikes:racing:france");
            }).thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
            }).thenCompose(res5 -> {
                System.out.println(res5); // >>> 3
                return asyncCommands.smembers("bikes:racing:france");
            })
                    .thenAccept(System.out::println)
                    // >>> [bike:1, bike:2, bike:3]
                    .toCompletableFuture();
            Mono<Void> sAddSMembers = reactiveCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
                    .doOnNext(result -> {
                        System.out.println(result); // >>> 3
                    }).flatMap(v -> reactiveCommands.smembers("bikes:racing:france").collectList()).doOnNext(result -> {
                        System.out.println(result); // >>> [bike:1, bike:2, bike:3]
                    }).then();
	rdb.Del(ctx, "bikes:racing:france")

	res9, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1", "bike:2", "bike:3").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res9) // >>> 3

	res10, err := rdb.SMembers(ctx, "bikes:racing:france").Result()

	if err != nil {
		panic(err)
	}

	// Sort the strings in the slice to make sure the output is lexicographical
	sort.Strings(res10)

	fmt.Println(res10) // >>> [bike:1 bike:2 bike:3]
        db.KeyDelete("bikes:racing:france");

        long res12 = db.SetAdd("bikes:racing:france", ["bike:1", "bike:2", "bike:3"]);
        RedisValue[] res13 = db.SetMembers("bikes:racing:france");
        Console.WriteLine(string.Join(", ", res13));    // >>> bike:3, bike:2, bike:1
        $r->del('bikes:racing:france');

        $res9 = $r->sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3']);
        echo $res9 . PHP_EOL;
        // >>> 3

        $res10 = $r->smembers('bikes:racing:france');
        sort($res10);
        echo json_encode($res10) . PHP_EOL;
        // >>> ["bike:1","bike:2","bike:3"]
r.del('bikes:racing:france')

res9 = r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
puts res9 # 3

res10 = r.smembers('bikes:racing:france')
puts res10.sort.inspect # ["bike:1", "bike:2", "bike:3"]
        let _: usize = r.del("bikes:racing:france").unwrap_or(0);

        if let Ok(res) = r.sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"]) {
            let res: usize = res;
            println!("{res}"); // >>> 3
        }

        if let Ok(res) = r.smembers("bikes:racing:france") {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1", "bike:2", "bike:3"]
        }
        let _: usize = r.del("bikes:racing:france").await.unwrap_or(0);

        if let Ok(res) = r.sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"]).await {
            let res: usize = res;
            println!("{res}"); // >>> 3
        }

        if let Ok(res) = r.smembers("bikes:racing:france").await {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1", "bike:2", "bike:3"]
        }

Here I've added three elements to my set and told Redis to return all the elements. There is no order guarantee with a set. Redis is free to return the elements in any order at every call.

Redis has commands to test for set membership. These commands can be used on single as well as multiple items:

Batch membership checks: Test multiple items at once using SMISMEMBER when you need to reduce round trips to the server
> SISMEMBER bikes:racing:france bike:1
(integer) 1
> SMISMEMBER bikes:racing:france bike:2 bike:3 bike:4
1) (integer) 1
2) (integer) 1
3) (integer) 0
res11 = r.sismember("bikes:racing:france", "bike:1")
print(res11)  # >>> 1

res12 = r.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4")
print(res12)  # >>> [1, 1, 0]
const res11 = await client.sIsMember('bikes:racing:france', 'bike:1')
console.log(res11)  // >>> 1

const res12 = await client.smIsMember('bikes:racing:france', ['bike:2', 'bike:3', 'bike:4'])
console.log(res12)  // >>> [1, 1, 0]
        boolean res11 = jedis.sismember("bikes:racing:france", "bike:1");
        System.out.println(res11);  // >>> true

        List<Boolean> res12 = jedis.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4");
        System.out.println(res12);  // >>> [true,true,false]
            CompletableFuture<Void> sMIsMember = sAddSMembers.thenCompose(r -> {
                return asyncCommands.sismember("bikes:racing:france", "bike:1");
            }).thenCompose(res6 -> {
                System.out.println(res6); // >>> True
                return asyncCommands.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4");
            })
                    .thenAccept(System.out::println) // >>> [true, true, false]
                    .toCompletableFuture();
            Mono<Boolean> sIsMember3 = reactiveCommands.sismember("bikes:racing:france", "bike:1").doOnNext(result -> {
                System.out.println(result); // >>> true
            });

            Mono<List<Boolean>> sMIsMember = reactiveCommands.smismember("bikes:racing:france", "bike:2", "bike:3", "bike:4")
                    .collectList().doOnNext(result -> {
                        System.out.println(result); // >>> [true, true, false]
                    });
	res11, err := rdb.SIsMember(ctx, "bikes:racing:france", "bike:1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res11) // >>> true

	res12, err := rdb.SMIsMember(ctx, "bikes:racing:france", "bike:2", "bike:3", "bike:4").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res12) // >>> [true true false]
        bool res14 = db.SetContains("bikes:racing:france", "bike:1");
        Console.WriteLine(res14);   // >>> true

        bool[] res15 = db.SetContains("bikes:racing:france", ["bike:2", "bike:3", "bike:4"]);
        Console.WriteLine(string.Join(", ", res15));    // >>> True, True, False
        $res11 = $r->sismember('bikes:racing:france', 'bike:1');
        echo $res11 . PHP_EOL;
        // >>> 1

        $res12 = $r->smismember('bikes:racing:france', 'bike:2', 'bike:3', 'bike:4');
        echo json_encode($res12) . PHP_EOL;
        // >>> [1,1,0]
res11 = r.sismember('bikes:racing:france', 'bike:1')
puts res11 # true

res12 = r.smismember('bikes:racing:france', 'bike:2', 'bike:3', 'bike:4')
puts res12.inspect # [true, true, false]
        if let Ok(res) = r.sismember("bikes:racing:france", "bike:1") {
            let res: bool = res;
            println!("{}", i32::from(res)); // >>> 1
        }

        if let Ok(res) = r.smismember("bikes:racing:france", &["bike:2", "bike:3", "bike:4"]) {
            let res: Vec<bool> = res;
            let res: Vec<i32> = res.into_iter().map(i32::from).collect();
            println!("{res:?}"); // >>> [1, 1, 0]
        }
        if let Ok(res) = r.sismember("bikes:racing:france", "bike:1").await {
            let res: bool = res;
            println!("{}", i32::from(res)); // >>> 1
        }

        if let Ok(res) = r
            .smismember("bikes:racing:france", &["bike:2", "bike:3", "bike:4"])
            .await
        {
            let res: Vec<bool> = res;
            let res: Vec<i32> = res.into_iter().map(i32::from).collect();
            println!("{res:?}"); // >>> [1, 1, 0]
        }

We can also find the difference between two sets. For instance, we may want to know which bikes are racing in France but not in the USA:

Set difference: Find members in one set but not in others using SDIFF when you need to exclude items (warning: argument order matters)
> SADD bikes:racing:usa bike:1 bike:4
(integer) 2
> SDIFF bikes:racing:france bikes:racing:usa
1) "bike:3"
2) "bike:2"
r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
r.sadd("bikes:racing:usa", "bike:1", "bike:4")

res13 = r.sdiff("bikes:racing:france", "bikes:racing:usa")
print(res13)  # >>> {'bike:2', 'bike:3'}
await client.del('bikes:racing:france')
await client.del('bikes:racing:usa')

await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
const res13 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
console.log(res13)  // >>> [ 'bike:2', 'bike:3' ]
        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");

        Set<String> res13 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa");
        System.out.println(res13);  // >>> [bike:2, bike:3]

            CompletableFuture<Void> sDiff = sMIsMember.thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
            }).thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:usa", "bike:1", "bike:4");
            }).thenCompose(r -> {
                return asyncCommands.sdiff("bikes:racing:france", "bikes:racing:usa");
            })
                    .thenAccept(System.out::println) // >>> [bike:2, bike:3]
                    .toCompletableFuture();
            Mono<List<String>> sDiff = reactiveCommands.sdiff("bikes:racing:france", "bikes:racing:usa").collectList()
                    .doOnNext(result -> {
                        System.out.println(result); // >>> [bike:2, bike:3]
                    });
	_, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1", "bike:2", "bike:3").Result()

	if err != nil {
		panic(err)
	}

	_, err = rdb.SAdd(ctx, "bikes:racing:usa", "bike:1", "bike:4").Result()

	res13, err := rdb.SDiff(ctx, "bikes:racing:france", "bikes:racing:usa").Result()

	if err != nil {
		panic(err)
	}

	// Sort the strings in the slice to make sure the output is lexicographical
	sort.Strings(res13)

	fmt.Println(res13) // >>> [bike:2 bike:3]
        long res16 = db.SetAdd("{bikes:racing}:france", ["bike:1", "bike:2", "bike:3"]);
        long res17 = db.SetAdd("{bikes:racing}:usa", ["bike:1", "bike:4"]);
        RedisValue[] res18 = db.SetCombine(SetOperation.Difference, ["{bikes:racing}:france", "{bikes:racing}:usa"]);
        Console.WriteLine(string.Join(", ", res18));    // >>> bike:2, bike:3
        $r->sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3']);
        $r->sadd('bikes:racing:usa', ['bike:1', 'bike:4']);

        $res13 = $r->sdiff(['bikes:racing:france', 'bikes:racing:usa']);
        sort($res13);
        echo json_encode($res13) . PHP_EOL;
        // >>> ["bike:2","bike:3"]
r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
r.sadd('bikes:racing:usa', ['bike:1', 'bike:4'])

res13 = r.sdiff('bikes:racing:france', 'bikes:racing:usa')
puts res13.sort.inspect # ["bike:2", "bike:3"]
        let _: usize = r.del("bikes:racing:france").unwrap_or(0);
        let _: usize = r.del("bikes:racing:usa").unwrap_or(0);
        let _: usize = r.sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"]).unwrap_or(0);
        let _: usize = r.sadd("bikes:racing:usa", &["bike:1", "bike:4"]).unwrap_or(0);

        if let Ok(res) = r.sdiff(&["bikes:racing:france", "bikes:racing:usa"]) {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:3"]
        }
        let _: usize = r.del("bikes:racing:france").await.unwrap_or(0);
        let _: usize = r.del("bikes:racing:usa").await.unwrap_or(0);
        let _: usize = r
            .sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"])
            .await
            .unwrap_or(0);
        let _: usize = r
            .sadd("bikes:racing:usa", &["bike:1", "bike:4"])
            .await
            .unwrap_or(0);

        if let Ok(res) = r.sdiff(&["bikes:racing:france", "bikes:racing:usa"]).await {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:3"]
        }

There are other non trivial operations that are still easy to implement using the right Redis commands. For instance we may want a list of all the bikes racing in France, the USA, and some other races. We can do this using the SINTER command, which performs the intersection between different sets. In addition to intersection you can also perform unions, difference, and more. For example if we add a third race we can see some of these commands in action:

Advanced pattern: Combine SINTER, SUNION, and SDIFF to analyze complex relationships when you need to precompute set algebra across multiple datasets
> DEL bikes:racing:france bikes:racing:usa bikes:racing:italy
(integer) 2
> SADD bikes:racing:france bike:1 bike:2 bike:3
(integer) 3
> SADD bikes:racing:usa bike:1 bike:4
(integer) 2
> SADD bikes:racing:italy bike:1 bike:2 bike:3 bike:4
(integer) 4
> SINTER bikes:racing:france bikes:racing:usa bikes:racing:italy
1) "bike:1"
> SUNION bikes:racing:france bikes:racing:usa bikes:racing:italy
1) "bike:2"
2) "bike:1"
3) "bike:4"
4) "bike:3"
> SDIFF bikes:racing:france bikes:racing:usa bikes:racing:italy
(empty array)
> SDIFF bikes:racing:france bikes:racing:usa
1) "bike:3"
2) "bike:2"
> SDIFF bikes:racing:usa bikes:racing:france
1) "bike:4"
r.delete("bikes:racing:france")
r.delete("bikes:racing:usa")
r.delete("bikes:racing:italy")

r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
r.sadd("bikes:racing:usa", "bike:1", "bike:4")
r.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4")

res13 = r.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
print(res13)  # >>> {'bike:1'}

res14 = r.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
print(res14)  # >>> {'bike:1', 'bike:2', 'bike:3', 'bike:4'}

res15 = r.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy")
print(res15)  # >>> set()

res16 = r.sdiff("bikes:racing:usa", "bikes:racing:france")
print(res16)  # >>> {'bike:4'}

res17 = r.sdiff("bikes:racing:france", "bikes:racing:usa")
print(res17)  # >>> {'bike:2', 'bike:3'}
await client.del('bikes:racing:france')
await client.del('bikes:racing:usa')
await client.del('bikes:racing:italy')

await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
await client.sAdd('bikes:racing:usa', ['bike:1', 'bike:4'])
await client.sAdd('bikes:racing:italy', ['bike:1', 'bike:2', 'bike:3', 'bike:4'])

const res14 = await client.sInter(
  ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
)
console.log(res14)  // >>> ['bike:1']

const res15 = await client.sUnion(
  ['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']
)
console.log(res15)  // >>> ['bike:1', 'bike:2', 'bike:3', 'bike:4']

const res16 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy'])
console.log(res16)  // >>> []

const res17 = await client.sDiff(['bikes:racing:usa', 'bikes:racing:france'])
console.log(res17)  // >>> ['bike:4']

const res18 = await client.sDiff(['bikes:racing:france', 'bikes:racing:usa'])
console.log(res18)  // >>> ['bike:2', 'bike:3']
        jedis.del("bikes:racing:france");
        jedis.del("bikes:racing:usa");
        jedis.del("bikes:racing:italy");

        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
        jedis.sadd("bikes:racing:usa", "bike:1", "bike:4");
        jedis.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4");

        Set<String> res14 = jedis.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res14);  // >>> [bike:1]

        Set<String> res15 = jedis.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res15);  // >>> [bike:1, bike:2, bike:3, bike:4]

        Set<String> res16 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
        System.out.println(res16);  // >>> []

        Set<String> res17 = jedis.sdiff("bikes:racing:usa", "bikes:racing:france");
        System.out.println(res17);  // >>> [bike:4]

        Set<String> res18 = jedis.sdiff("bikes:racing:france", "bikes:racing:usa");
        System.out.println(res18);  // >>> [bike:2, bike:3]

            CompletableFuture<Void> multisets = sDiff.thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3");
            }).thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:usa", "bike:1", "bike:4");
            }).thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4");
            }).thenCompose(r -> {
                return asyncCommands.sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
            }).thenCompose(res7 -> {
                System.out.println(res7); // >>> [bike:1]
                return asyncCommands.sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
            }).thenCompose(res8 -> {
                System.out.println(res8);
                // >>> [bike:1, bike:2, bike:3, bike:4]
                return asyncCommands.sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy");
            }).thenCompose(res9 -> {
                System.out.println(res9); // >>> []
                return asyncCommands.sdiff("bikes:racing:usa", "bikes:racing:france");
            }).thenCompose(res10 -> {
                System.out.println(res10); // >>> [bike:4]
                return asyncCommands.sdiff("bikes:racing:france", "bikes:racing:usa");
            })
                    .thenAccept(System.out::println) // >>> [bike:2, bike:3]
                    .toCompletableFuture();
            Mono<Void> add3sets = reactiveCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3")
                    .doOnNext(result -> {
                        System.out.println(result); // >>> 0
                    }).flatMap(v -> reactiveCommands.sadd("bikes:racing:usa", "bike:1", "bike:4")).doOnNext(result -> {
                        System.out.println(result); // >>> 0
                    }).flatMap(v -> reactiveCommands.sadd("bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4"))
                    .doOnNext(result -> {
                        System.out.println(result); // >>> 4,
                    }).then();
            add3sets.block();

            Mono<List<String>> multisets1 = reactiveCommands
                    .sinter("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").collectList().doOnNext(result -> {
                        System.out.println(result); // >>> [bike:1]
                    });

            Mono<List<String>> multisets2 = reactiveCommands
                    .sunion("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").collectList().doOnNext(result -> {
                        System.out.println(result); // >>> [bike:1, bike:2, bike:3, bike:4]
                    });

            Mono<List<String>> multisets3 = reactiveCommands
                    .sdiff("bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").collectList().doOnNext(result -> {
                        System.out.println(result); // >>> []
                    });

            Mono<List<String>> multisets4 = reactiveCommands.sdiff("bikes:racing:usa", "bikes:racing:france").collectList()
                    .doOnNext(result -> {
                        System.out.println(result); // >>> [bike:4]
                    });

            Mono<List<String>> multisets5 = reactiveCommands.sdiff("bikes:racing:france", "bikes:racing:usa").collectList()
                    .doOnNext(result -> {
                        System.out.println(result); // >>> [bike:2, bike:3]
                    });
	rdb.Del(ctx, "bikes:racing:france")
	rdb.Del(ctx, "bikes:racing:usa")
	rdb.Del(ctx, "bikes:racing:italy")

	_, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1", "bike:2", "bike:3").Result()

	if err != nil {
		panic(err)
	}

	_, err = rdb.SAdd(ctx, "bikes:racing:usa", "bike:1", "bike:4").Result()

	if err != nil {
		panic(err)
	}

	_, err = rdb.SAdd(ctx, "bikes:racing:italy", "bike:1", "bike:2", "bike:3", "bike:4").Result()

	if err != nil {
		panic(err)
	}

	res14, err := rdb.SInter(ctx, "bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res14) // >>> [bike:1]

	res15, err := rdb.SUnion(ctx, "bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").Result()

	if err != nil {
		panic(err)
	}

	// Sort the strings in the slice to make sure the output is lexicographical
	sort.Strings(res15)

	fmt.Println(res15) // >>> [bike:1 bike:2 bike:3 bike:4]

	res16, err := rdb.SDiff(ctx, "bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res16) // >>> []

	res17, err := rdb.SDiff(ctx, "bikes:racing:usa", "bikes:racing:france").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res17) // >>> [bike:4]

	res18, err := rdb.SDiff(ctx, "bikes:racing:france", "bikes:racing:usa").Result()

	if err != nil {
		panic(err)
	}

	// Sort the strings in the slice to make sure the output is lexicographical
	sort.Strings(res18)

	fmt.Println(res18) // >>> [bike:2 bike:3]
        db.KeyDelete("{bikes:racing}:france");
        db.KeyDelete("{bikes:racing}:usa");
        db.KeyDelete("{bikes:racing}:italy");

        long res19 = db.SetAdd("{bikes:racing}:france", ["bike:1", "bike:2", "bike:3"]);
        long res20 = db.SetAdd("{bikes:racing}:usa", ["bike:1", "bike:4"]);
        long res21 = db.SetAdd("{bikes:racing}:italy", ["bike:1", "bike:2", "bike:3", "bike:4"]);

        RedisValue[] res22 = db.SetCombine(SetOperation.Intersect, ["{bikes:racing}:france", "{bikes:racing}:usa", "{bikes:racing}:italy"
        ]);
        Console.WriteLine(string.Join(", ", res22));    // >>> bike:1

        RedisValue[] res23 = db.SetCombine(SetOperation.Union, ["{bikes:racing}:france", "{bikes:racing}:usa", "{bikes:racing}:italy"
        ]);
        Console.WriteLine(string.Join(", ", res23));    // >>> bike:1, bike:2, bike:3, bike:4

        RedisValue[] res24 = db.SetCombine(SetOperation.Difference, ["{bikes:racing}:france", "{bikes:racing}:usa", "{bikes:racing}:italy"
        ]);
        Console.WriteLine(string.Join(", ", res24));    // >>> <empty set>

        RedisValue[] res25 = db.SetCombine(SetOperation.Difference, ["{bikes:racing}:usa", "{bikes:racing}:france"]);
        Console.WriteLine(string.Join(", ", res25));    // >>> bike:4

        RedisValue[] res26 = db.SetCombine(SetOperation.Difference, ["{bikes:racing}:france", "{bikes:racing}:usa"]);
        Console.WriteLine(string.Join(", ", res26));    // >>> bike:2, bike:3
        $r->del('bikes:racing:france');
        $r->del('bikes:racing:usa');
        $r->del('bikes:racing:italy');
            
        $r->sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3']);
        $r->sadd('bikes:racing:usa', ['bike:1', 'bike:4']);
        $r->sadd('bikes:racing:italy', ['bike:1', 'bike:2', 'bike:3', 'bike:4']);

        $res14 = $r->sinter(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']);
        echo json_encode($res14) . PHP_EOL;
        // >>> ["bike:1"]

        $res15 = $r->sunion(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']);
        sort($res15);
        echo json_encode($res15) . PHP_EOL;
        // >>> ["bike:1","bike:2","bike:3","bike:4"]

        $res16 = $r->sdiff(['bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy']);
        echo json_encode($res16) . PHP_EOL;
        // >>> []

        $res17 = $r->sdiff(['bikes:racing:usa', 'bikes:racing:france']);
        echo json_encode($res17) . PHP_EOL;
        // >>> ["bike:4"]

        $res18 = $r->sdiff(['bikes:racing:france', 'bikes:racing:usa']);
        sort($res18);
        echo json_encode($res18) . PHP_EOL;
        // >>> ["bike:2","bike:3"]
r.del('bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy')

r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3'])
r.sadd('bikes:racing:usa', ['bike:1', 'bike:4'])
r.sadd('bikes:racing:italy', ['bike:1', 'bike:2', 'bike:3', 'bike:4'])

res14 = r.sinter('bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy')
puts res14.inspect # ["bike:1"]

res15 = r.sunion('bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy')
puts res15.sort.inspect # ["bike:1", "bike:2", "bike:3", "bike:4"]

res16 = r.sdiff('bikes:racing:france', 'bikes:racing:usa', 'bikes:racing:italy')
puts res16.inspect # []

res17 = r.sdiff('bikes:racing:france', 'bikes:racing:usa')
puts res17.sort.inspect # ["bike:2", "bike:3"]

res18 = r.sdiff('bikes:racing:usa', 'bikes:racing:france')
puts res18.inspect # ["bike:4"]
        let _: usize = r.del(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"]).unwrap_or(0);
        let _: usize = r.sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"]).unwrap_or(0);
        let _: usize = r.sadd("bikes:racing:usa", &["bike:1", "bike:4"]).unwrap_or(0);
        let _: usize = r.sadd("bikes:racing:italy", &["bike:1", "bike:2", "bike:3", "bike:4"]).unwrap_or(0);

        if let Ok(res) =
            r.sinter(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1"]
        }

        if let Ok(res) =
            r.sunion(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1", "bike:2", "bike:3", "bike:4"]
        }

        if let Ok(res) =
            r.sdiff(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> []
        }

        if let Ok(res) = r.sdiff(&["bikes:racing:france", "bikes:racing:usa"]) {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:3"]
        }

        if let Ok(res) = r.sdiff(&["bikes:racing:usa", "bikes:racing:france"]) {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:4"]
        }
        let _: usize = r
            .del(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
            .await
            .unwrap_or(0);
        let _: usize = r
            .sadd("bikes:racing:france", &["bike:1", "bike:2", "bike:3"])
            .await
            .unwrap_or(0);
        let _: usize = r
            .sadd("bikes:racing:usa", &["bike:1", "bike:4"])
            .await
            .unwrap_or(0);
        let _: usize = r
            .sadd("bikes:racing:italy", &["bike:1", "bike:2", "bike:3", "bike:4"])
            .await
            .unwrap_or(0);

        if let Ok(res) = r
            .sinter(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
            .await
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1"]
        }

        if let Ok(res) = r
            .sunion(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
            .await
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:1", "bike:2", "bike:3", "bike:4"]
        }

        if let Ok(res) = r
            .sdiff(&["bikes:racing:france", "bikes:racing:usa", "bikes:racing:italy"])
            .await
        {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> []
        }

        if let Ok(res) = r.sdiff(&["bikes:racing:france", "bikes:racing:usa"]).await {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:3"]
        }

        if let Ok(res) = r.sdiff(&["bikes:racing:usa", "bikes:racing:france"]).await {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:4"]
        }

You'll note that the SDIFF command returns an empty array when the difference between all sets is empty. You'll also note that the order of sets passed to SDIFF matters, since the difference is not commutative.

When you want to remove items from a set, you can use the SREM command to remove one or more items from a set, or you can use the SPOP command to remove a random item from a set. You can also return a random item from a set without removing it using the SRANDMEMBER command:

Removal strategies: Use SREM for targeted removal, SPOP for random removal, or SRANDMEMBER to inspect without modifying when you need flexible deletion patterns
> DEL bikes:racing:france
(integer) 1
> SADD bikes:racing:france bike:1 bike:2 bike:3 bike:4 bike:5
(integer) 5
> SREM bikes:racing:france bike:1
(integer) 1
> SPOP bikes:racing:france
"bike:3"
> SMEMBERS bikes:racing:france
1) "bike:2"
2) "bike:4"
3) "bike:5"
> SRANDMEMBER bikes:racing:france
"bike:2"
r.delete("bikes:racing:france")

r.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5")

res18 = r.srem("bikes:racing:france", "bike:1")
print(res18)  # >>> 1

res19 = r.spop("bikes:racing:france")
print(res19)  # >>> bike:3

res20 = r.smembers("bikes:racing:france")
print(res20)  # >>> {'bike:2', 'bike:4', 'bike:5'}

res21 = r.srandmember("bikes:racing:france")
print(res21)  # >>> bike:4
await client.del('bikes:racing:france')

await client.sAdd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5'])

const res19 = await client.sRem('bikes:racing:france', 'bike:1')
console.log(res19)  // >>> 1

const res20 = await client.sPop('bikes:racing:france')
console.log(res20)  // >>> bike:3 or other random value

const res21 = await client.sMembers('bikes:racing:france')
console.log(res21)  // >>> ['bike:2', 'bike:4', 'bike:5']; depends on previous result

const res22 = await client.sRandMember('bikes:racing:france')
console.log(res22)  // >>> bike:4 or other random value
        jedis.del("bikes:racing:france");
        jedis.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");

        long res19 = jedis.srem("bikes:racing:france", "bike:1");
        System.out.println(res18);  // >>> 1

        String res20 = jedis.spop("bikes:racing:france");
        System.out.println(res20);  // >>> bike:3

        Set<String> res21 = jedis.smembers("bikes:racing:france");
        System.out.println(res21);  // >>> [bike:2, bike:4, bike:5]

        String res22 = jedis.srandmember("bikes:racing:france");
        System.out.println(res22);  // >>> bike:4
            CompletableFuture<Void> sRem = multisets.thenCompose(r -> {
                return asyncCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5");
            }).thenCompose(r -> {
                return asyncCommands.srem("bikes:racing:france", "bike:1");
            }).thenCompose(res11 -> {
                System.out.println(res11); // >>> 1
                return asyncCommands.spop("bikes:racing:france");
            }).thenCompose(res12 -> {
                System.out.println(res12); // >>> bike:3 (for example)
                return asyncCommands.smembers("bikes:racing:france");
            }).thenCompose(res13 -> {
                System.out.println(res13); // >>> [bike:2, bike:4, bike:5]
                return asyncCommands.srandmember("bikes:racing:france");
            }).thenAccept(System.out::println) // >>> bike:4
                    .toCompletableFuture();
            Mono<Void> sRem = reactiveCommands.sadd("bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5")
                    .doOnNext(result -> {
                        System.out.println(result); // >>> 2
                    }).flatMap(v -> reactiveCommands.srem("bikes:racing:france", "bike:1")).doOnNext(result -> {
                        System.out.println(result); // >>> 1
                    }).flatMap(v -> reactiveCommands.spop("bikes:racing:france")).doOnNext(result -> {
                        System.out.println(result); // >>> bike:3 (for example)
                    }).flatMap(v -> reactiveCommands.smembers("bikes:racing:france").collectList()).doOnNext(result -> {
                        System.out.println(result); // >>> [bike:2, bike:4, bike:5] (for example)
                    }).flatMap(v -> reactiveCommands.srandmember("bikes:racing:france")).doOnNext(result -> {
                        System.out.println(result); // >>> bike:4 (for example)
                    }).then();
	rdb.Del(ctx, "bikes:racing:france")

	_, err := rdb.SAdd(ctx, "bikes:racing:france", "bike:1", "bike:2", "bike:3", "bike:4", "bike:5").Result()

	if err != nil {
		panic(err)
	}

	res19, err := rdb.SRem(ctx, "bikes:racing:france", "bike:1").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res19) // >>> 1

	res20, err := rdb.SPop(ctx, "bikes:racing:france").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res20) // >>> <random element>

	res21, err := rdb.SMembers(ctx, "bikes:racing:france").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res21) // >>> <remaining elements>

	res22, err := rdb.SRandMember(ctx, "bikes:racing:france").Result()

	if err != nil {
		panic(err)
	}

	fmt.Println(res22) // >>> <random element>
        db.KeyDelete("bikes:racing:france");

        long res27 = db.SetAdd("bikes:racing:france", ["bike:1", "bike:2", "bike:3", "bike:4", "bike:5"]);

        bool res28 = db.SetRemove("bikes:racing:france", "bike:1");
        Console.WriteLine(res28);   // >>> True

        RedisValue res29 = db.SetPop("bikes:racing:france");
        Console.WriteLine(res29);   // >>> bike:3

        RedisValue[] res30 = db.SetMembers("bikes:racing:france");
        Console.WriteLine(string.Join(", ", res30));    // >>> bike:2, bike:4, bike:5

        RedisValue res31 = db.SetRandomMember("bikes:racing:france");
        Console.WriteLine(res31);   // >>> bike:4
        $r->del('bikes:racing:france');

        $r->sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5']);

        $res19 = $r->srem('bikes:racing:france', ['bike:1']);
        echo $res19 . PHP_EOL;
        // >>> 1

        $res20 = $r->spop('bikes:racing:france');
        echo $res20 . PHP_EOL;
        // >>> bike:3 (for example)

        $res21 = $r->smembers('bikes:racing:france');
        sort($res21);
        echo json_encode($res21) . PHP_EOL;
        // >>> ["bike:2","bike:4","bike:5"]

        $res22 = $r->srandmember('bikes:racing:france');
        echo $res22 . PHP_EOL;
        // >>> bike:4 (for example)

r.del('bikes:racing:france')

r.sadd('bikes:racing:france', ['bike:1', 'bike:2', 'bike:3', 'bike:4', 'bike:5'])

res19 = r.srem('bikes:racing:france', ['bike:1'])
puts res19 # 1

res20 = r.spop('bikes:racing:france')
puts res20 # bike:3, for example

res21 = r.smembers('bikes:racing:france')
puts res21.sort.inspect # Remaining members, in no particular order

res22 = r.srandmember('bikes:racing:france')
puts res22 # bike:4, for example
        let _: usize = r.del("bikes:racing:france").unwrap_or(0);
        let _: usize = r
            .sadd(
                "bikes:racing:france",
                &["bike:1", "bike:2", "bike:3", "bike:4", "bike:5"],
            )
            .unwrap_or(0);

        if let Ok(res) = r.srem("bikes:racing:france", "bike:1") {
            let res: usize = res;
            println!("{res}"); // >>> 1
        }

        if let Ok(res) = r.spop("bikes:racing:france") {
            let res: Option<String> = res;
            match res {
                Some(res) => println!("{res}"), // >>> bike:3 (for example)
                None => println!("(nil)"),
            }
        }

        if let Ok(res) = r.smembers("bikes:racing:france") {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:4", "bike:5"] (for example)
        }

        if let Ok(res) = r.srandmember("bikes:racing:france") {
            let res: Option<String> = res;
            match res {
                Some(res) => println!("{res}"), // >>> bike:4 (for example)
                None => println!("(nil)"),
            }
        }
        let _: usize = r.del("bikes:racing:france").await.unwrap_or(0);
        let _: usize = r
            .sadd(
                "bikes:racing:france",
                &["bike:1", "bike:2", "bike:3", "bike:4", "bike:5"],
            )
            .await
            .unwrap_or(0);

        if let Ok(res) = r.srem("bikes:racing:france", "bike:1").await {
            let res: usize = res;
            println!("{res}"); // >>> 1
        }

        if let Ok(res) = r.spop("bikes:racing:france").await {
            let res: Option<String> = res;
            match res {
                Some(res) => println!("{res}"), // >>> bike:3 (for example)
                None => println!("(nil)"),
            }
        }

        if let Ok(res) = r.smembers("bikes:racing:france").await {
            let res: HashSet<String> = res;
            let res = sorted_set(res);
            println!("{res:?}"); // >>> ["bike:2", "bike:4", "bike:5"] (for example)
        }

        if let Ok(res) = r.srandmember("bikes:racing:france").await {
            let res: Option<String> = res;
            match res {
                Some(res) => println!("{res}"), // >>> bike:4 (for example)
                None => println!("(nil)"),
            }
        }

Limits

The max size of a Redis set is 2^32 - 1 (4,294,967,295) members.

Performance

Most set operations, including adding, removing, and checking whether an item is a set member, are O(1). This means that they're highly efficient. However, for large sets with hundreds of thousands of members or more, you should exercise caution when running the SMEMBERS command. This command is O(n) and returns the entire set in a single response. As an alternative, consider the SSCAN, which lets you retrieve all members of a set iteratively.

Alternatives

Sets membership checks on large datasets (or on streaming data) can use a lot of memory. If you're concerned about memory usage and don't need perfect precision, consider a Bloom filter or Cuckoo filter as an alternative to a set.

Redis sets are frequently used as a kind of index. If you need to index and query your data, consider the JSON data type and the Redis Search features.

Learn more

RATE THIS PAGE
Back to top ↑