redis-cli コマンド操作まとめ

## redis-cli コマンド操作まとめ

redis-cliを使用したredisのコマンドについてまとめました。
この記事で説明するコマンドは下記の環境で動作確認を行いました。

* windows7 (64bit)
* redis 2.8.19

**コマンドの実行例**

各コマンド毎に動作確認を行った簡単な実行例を記述しています。
例中にはありませんがその都度`flushall`コマンドにてキーを削除してから動作確認を行いました。

```c:example
> flushall
OK

> set mykey1 "abc"
OK
> get mykey1
"abc"
```

### インストールと設定

#### インストール

[MSOpenTech] (https://github.com/MSOpenTech/redis/releases)より、アーカイブファイルをダウンロードします。
この記事ではredis-2.8.19.zipを使用しました。

適当なフォルダへ解凍して終了です。この例では`C:/redis-2-8.19`にしました。

#### 設定

下記の内容でredis.confを編集しました。

**ログ**

```text
loglevel notice
logfile "C:/redis-2.8.19/log/redis.log"
```

**データベースファイル**

```text
dbfilename dump.rdb
dir "C:/redis-2.8.19/db"
```

**AOFファイル**

```text
appendonly yes
appendfilename "appendonly.aof"
appendfsync everysec
```

## command

キーと5つのデータ型(strings、hashes、sets、sorted sets、lists)のコマンドを説明します。

|data type   |扱う要素                               |
|:-----------|:-------------------------------------|
|文字列      |_key_ に `value`を登録                 |
|ハッシュ    |_key_ に `field`と`value`をペアで登録   |
|セット      |_key_ に `member`を登録                |
|ソート済みセット|_key_ に `member`と`score`をペアで登録  |
|リスト      |_key_ に `value`を登録                 |

### 文字列

文字列型の特徴

* 1つの文字列の最大サイズは512MBです。
* 値に追記することができます。
* 値をINCR/DECRコマンドでカウンタとして使用できます。
* 他のデータ型(ハッシュ、セット、ソート済みセット、リスト)が保持する要素のデータ型です。

#### 基本操作

##### SET / SETNX / GET

**キーと値の登録、取得を行います**

```text:syntax
SET key value [EX seconds] [PX milliseconds] [NX|XX]
SETNX key value
GET key
```

`set`コマンドで値を登録し`get`コマンドで値を取得します。
`setnx`コマンドは既存のキーに値を登録することはできません。(update不可)

```c:SET_GET_SETNX
> set mystr1 "abc"
OK
> get mystr1
"abc"

// このキーは存在するので更新はされません
> setnx mystr1 "def"
(integer) 0
> get mystr1
"abc"

// 新しいキーの登録はできます
> setnx mystr2 "def"
(integer) 1
> get mystr2
"def"
```

##### SETEX / PSETEX

**キーに有効期限を設定して値を登録します**

```text:syntax
SETEX key seconds value
PSETEX key milliseconds value
```

`setex`コマンドはキーに有効期限を秒単位で設定します。
`ttl`コマンドは(文字型に限らず)キーに設定された有効期限を確認できます。

```c:SETEX
// キーに10秒の期限を設定して登録します
> setex mystr1 10 "abc"
OK

// 有効期限を確認します、この時点で残り6秒ということがわかります
> ttl mystr1
(integer) 6

// （有効期限切れで）キーが存在しない場合は-2が返ります
> ttl mystr1
(integer) -2
> get mystr1
(nil)
```

`psetex`コマンドはキーに有効期限をミリ秒単位で設定します。
`pttl`コマンドは(文字列型に限らず)キーに設定された有効期限を確認できます。

```c:PSETEX
// キーに10000ミリ秒(10秒)の有効期限を設定して登録します
> psetex mystr1 10000 "abc"
OK

// 有効期限を確認します、この時点で残り8109ミリ秒ということがわかります
> pttl mystr1
(integer) 8109

// （有効期限切れで）キーが存在しない場合は-2が返ります
> pttl mystr1
(integer) -2
> get mystr1
(nil)
```

##### GETSET

**値の取得と更新を同時に行います**

```text:syntax
GETSET key value
```

キーから値を取得した後に新しい値を登録します。
キーが存在しない場合は`nil`が返ります。

```c:GETSET
// 新規に登録する場合はnilが返ります
> getset mystr1 "abc"
(nil)

// 現在の値を取得し新しい値を登録します
> getset mystr1 "def"
"abc"
> getset mystr1 "ghi"
"def"
> get mystr1
"ghi"
```

##### STRLEN

**値の長さを取得します**

```text:syntax
STRLEN key
```

```c:STRLEN
// 存在しないキーは0が返ります
> strlen mystr1
(integer) 0

> set mystr1 "abcdef"
OK
> strlen mystr1
(integer) 6
```

マニュアルには記載はありませんが`strlen`はバイト数を返すようです。

> [redis command - strlen] (http://redis.io/commands/strlen)
> Returns the length of the string value stored at key.

ためしにコンソールから日本語を入力してみます。文字データ長は9となりました。

```c:STRLEN_MULTIBYTE
// "うまい棒A"を登録してみます。（画面上では文字化けすると思います）
> set mystr2 "うまい棒A"
OK
// 取得するとシリアライズされた結果が表示されますが問題ありません
> get mystr2
"\x82\xa4\x82\xdc\x82\xa2\x96_A"
 
> strlen mystr2
(integer) 9
```

コンソールでは"うまい棒"は文字化けして表示されますが、下記のように`--raw`オプションを付けると正常に値を取得することができます。

```bash
> redis-cli.exe --raw get mystr2
うまい棒A

> redis-cli.exe strlen mystr2
9
```

**UTF-8の場合**

上記の例の文字コードはSJIS(CP932)ですが、UTF-8のときはどうなるか確認しました。

utf8sample.txtというテキストファイルに下記のコマンドを記述してUTF-8で保存します。

```text:utf8sample.txt
set mystr3 "うまい棒A"
```

UTF-8のときの文字データ長は13となりました。

```bash
// ファイルに記述したコマンドを送り込みます
> redis-cli.exe < utf8sample.txt
OK

// コンソールでは文字化けするので一旦テキストファイルへ保存します
// res.txtをUTF-8で開くと"うまい棒A"と表示されます
> redis-cli.exe --raw get mystr3 > res.txt

> redis-cli.exe strlen mystr3
(integer) 13
```

#### マルチ操作

##### MSET / MSETNX

**一度に複数のキーと値を登録します**

```text:syntax
MSET key value [key value ...]
MSETNX key value [key value ...]
```

```c:MSET
// 1度に2つのキーを登録します
> mset mystr1 "abc" mystr2 "def"
OK

// 登録できてることを確認します
> get mystr1
"abc"
> get mystr2
"def"

// 更新と追加を行います。
> mset mystr2 "DEF" mystr3 "ghi"
OK
> get mystr2
"DEF"
> get mystr3
"ghi"
```

`MSETNX`は指定したキーがすべて存在しなければ値の登録を行います。
もし1つでもキーが存在していると何も行われません。

```c:MSETNX
// 2つのキーを登録します
> msetnx mystr1 "abc" mystr2 "def"
(integer) 1

// 登録できていることを確認します
> get mystr1
"abc"
> get mystr2
"def"

// 2つのキーの値を更新、3つ目のキーを追加しますが既存のキーがあるため何もおこなわれません
> msetnx mystr1 "ABC" mystr2 "DEF" mystr3 "GHI"
(integer) 0

// 2つの値は更新されず、3つ目のキーは登録されません
> get mystr1
"abc"
> get mystr2
"def"
> get mystr3
(nil)
```

##### MGET

**一度に複数のキーの値を取得します**

```text:syntax
MGET key [key ...]
```

```c:MGET
> mset mystr1 "abc" mystr2 "def"
OK

// 1度に複数の値を取得できます
> mget mystr1 mystr2
1) "abc"
2) "def"

// 存在しないキーはnilが返ります
> mget mystr1 mystr2 mystr3
1) "abc"
2) "def"
3) (nil)
```

#### 部分操作

**インデックス**

* 文字列を先頭から見た場合、0から始まり1、2と続きます。
* 文字列を末尾から見た場合、-1から始まり、-2、-3と続きます。

先頭文字はインデックス:0、末尾文字はインデックス:-1で示すことができ、start:0からend:-1は文字列全体を指します。

**サンプルデータ**

```text:sample_data_image
> SET mystr1 "abcdefghi"

 +--[ key:mystr1 ]--------------------------------------------+
 |                                                            |
 | (from the first of the string)                             |
 |  index ->  0   1   2   3   4   5   6   7   8               |
 |           +---+---+---+---+---+---+---+---+---+            |
 |           | a | b | c | d | e | f | g | h | i |            |
 |           +---+---+---+---+---+---+---+---+---+            |
 |             -9  -8  -7  -6  -5  -4  -3  -2  -1  <- index   |
 |                              (from the end of the string)  |
 +------------------------------------------------------------+
```

##### SETRANGE

**値の一部分を別の値で更新します**

```text:syntax
SETRANGE key offset value
```

offsetで更新位置を指定します。0を指定すると先頭位置からvalueで更新します。

```c:SETRANGE
> set mystr1 "abcdefghi"
OK

//offset:3の位置から"DEF"で更新します
> setrange mystr1 3 "DEF"
(integer) 9
> get mystr1
"abcDEFghi"
```

offsetを値の末端に指定すると値の追記になります。
また、offsetを文字列長より大きい値にするとzero-bytesで埋め合わされます。

> If the offset is larger than the current length of the string at key, the string is padded with zero-bytes to make offset fit.

```c:SETRANGE
> set mystr1 "abcdefghi"
OK

// offsetを値の末端にするとvalueは追記される形になります
> setrange mystr1 9 "JKL"
(integer) 12
> get mystr1
"abcdefghiJKL"

// offsetを文字長より大きい値にするとその間はzero-bytesで埋められます
> setrange mystr1 13 "mno"
(integer) 16
> get mystr1
"abcdefghiJKL\x00mno"
```

##### GETRANGE

**値の一部分を取得します**

```text:syntax
GETRANGE key start end
```

範囲をstart、endで指定した部分の値を取得します。

```c:GETRANGE
> set mystr1 "abcdefghi"
OK

// start:0からend:2までの値を取得します
> getrange mystr1 0 2
"abc"

// -1は値の最後の文字を表しますので、start:0からend:-1は値全体のことになります
> getrange mystr1 0 -1
"abcdefghi"
```

##### APPEND

**値に新しい値を追加します**

```text:syntax
APPEND key value
```

```c:APPEND
> set mystr1 "abc"
OK

> append mystr1 "def"
(integer) 6
> get mystr1
"abcdef"
```

存在しないキーへのAPPENDは値の登録になります。

```c:APPEND
// 存在しないキーの場合はsetコマンドと同じ結果になります
> append mystr2 "def"
(integer) 3
> get mystr2
"def"
```

#### インクリメント

##### INCR / INCRBY / INCRBYFLOAT

**値をインクリメントします**

```text:syntax
INCR key
INCRBY key increment
INCRBYFLOAT key increment
```

値が整数として表現できる場合、値に1を加算します。

```c:INCR
// 初期値として0を登録します
> set myint1 "0"
OK
> get myint1
"0"

// インクリメントします
> incr myint1
(integer) 1
> incr myint1
(integer) 2
> get myint1
"2"
```

値が整数として表現できない場合、エラーが発生します。

```c:INCR
> set myint2 "a"
OK
> get myint2
"a"

// 整数として表現できない場合はエラーが返ります
> incr myint2
(error) ERR value is not an integer or out of range
```

incrementで指定した整数で値を加算します。

```c:INCRBY
// 初期値に0を登録します
> set myint3 "0"
OK

// インクリメントします
> incrby myint3 2
(integer) 2
> incrby myint3 2
(integer) 4
> incrby myint3 2
(integer) 6
> get myint3
"6"
```

incrementで指定した浮動小数点数で値を加算します。

```c:INCRBYFLOAT
// 初期値に10を登録します
> set myflt1 "10"
OK
> get myflt1
"10"

// インクリメントします
> incrbyfloat myflt1 1.1
"11.1"
> incrbyfloat myflt1 0.5
"11.6"
> get myflt1
"11.6"
```

#### デクリメント

##### DECR / DECRBY

**値をデクリメントします**

```text:syntax
DECR key
DECRBY key decrement
```

値が整数として表現できる場合、値から1を減算します。

```c:DECR
// 初期値として10を登録します
> set myint1 "10"
OK
> get myint1
"10"

// デクリメントします
> decr myint1
(integer) 9
> decr myint1
(integer) 8
> get myint1
"8"
```

incrementで指定した整数で値から減算します。

```c:DECRBY
// 初期値に10を登録します
> set myint2 "10"
OK

// デクリメントします。
> decrby myint2 4
(integer) 6
> decrby myint2 4
(integer) 2
> decrby myint2 4
(integer) -2
> get myint2
"-2"
```

#### ビット演算

##### SETBIT

**ビットのセットとクリアを行います**

```text:syntax
SETBIT key offset value
```

offsetにビット操作を行う位置を指定します。指定できる範囲は0から2の32乗(4,294,967,296)です。
valueにセットの場合は1、クリアの場合は0を指定します。

```c:SETBIT
// offset:0の位置のビットをセットします、返り値は更新する前のビットです
> setbit mybit1 0 1
(integer) 0

// offset:0の位置のビットをクリアします
> setbit mybit1 0 0
(integer) 1
> setbit mybit1 0 0
(integer) 0
```

##### GETBIT

**指定位置のビットを取得します**

```text:syntax
GETBIT key offset
```

```c:GETBIT
> setbit mybit2 0 1
(integer) 0
> setbit mybit2 1 0
(integer) 0
> setbit mybit2 2 0
(integer) 0
> setbit mybit2 3 1
(integer) 0
> setbit mybit2 4 1
(integer) 0
> setbit mybit2 5 0
(integer) 0

> getbit mybit2 0
(integer) 1
> getbit mybit2 1
(integer) 0
> getbit mybit2 2
(integer) 0
> getbit mybit2 3
(integer) 1
> getbit mybit2 4
(integer) 1
> getbit mybit2 5
(integer) 0
```

##### BITCOUNT

**ビットがセットされた件数を取得します**

```text:syntax
BITCOUNT key [start end]
```

```c:BITCOUNT
> setbit mybit3 0 1
(integer) 0
> setbit mybit3 1 0
(integer) 0
> setbit mybit3 2 0
(integer) 0
> setbit mybit3 3 1
(integer) 0
> setbit mybit3 4 1
(integer) 0
> setbit mybit3 5 0
(integer) 0

// セットされているビットをカウントします
> bitcount mybit3
(integer) 3

// 新しくビットをセットしてもう一度カウントしてみます
> setbit mybit3 5 1
(integer) 0
> bitcount mybit3
(integer) 4

// キーが存在しない場合は0が返ります
> bitcount mybit4
(integer) 0
```

##### BITOP

**ビット演算を行います**

```text:syntax
BITOP operation destkey key [key ...]
```

***operation***

|operation|description                            |
|:--------|:--------------------------------------|
|AND      |両方のビットが共に1のときに1をセットします |
|OR       |どちらかのビットが1のときに1をセットします |
|XOR      |両方のビットが異なるときに1をセットします  |
|NOT      |ビットを反転します          |


***サンプルデータ***

```text:sample_data_image
> BITSET mybit1 0 0
> BITSET mybit1 1 0
> BITSET mybit1 2 0
> BITSET mybit1 3 0
> BITSET mybit1 4 1
> BITSET mybit1 5 1
> BITSET mybit1 6 1
> BITSET mybit1 7 1

> BITSET mybit2 0 0
> BITSET mybit2 1 0
> BITSET mybit2 2 1
> BITSET mybit2 3 1
> BITSET mybit2 4 0
> BITSET mybit2 5 0
> BITSET mybit2 6 1
> BITSET mybit2 7 1

> BITSET mybit3 0 0
> BITSET mybit3 1 1
> BITSET mybit3 2 0
> BITSET mybit3 3 1
> BITSET mybit3 4 0
> BITSET mybit3 5 1
> BITSET mybit3 6 0
> BITSET mybit3 7 1

           +---+---+---+---+---+---+---+---+
           | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | <- index
   +-------+---+---+---+---+---+---+---+---+
   |mybit1 | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
   +-------+---+---+---+---+---+---+---+---+
   |mybit2 | 0 | 0 | 1 | 1 | 0 | 0 | 1 | 1 |
   +-------+---+---+---+---+---+---+---+---+
   |mybit3 | 0 | 1 | 0 | 1 | 0 | 1 | 0 | 1 |
   +-------+---+---+---+---+---+---+---+---+

演算結果
   +-------+---+---+---+---+---+---+---+---+
   | AND   | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 1 |
   +-------+---+---+---+---+---+---+---+---+
   | OR    | 0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
   +-------+---+---+---+---+---+---+---+---+
   | XOR   | 0 | 1 | 1 | 0 | 1 | 0 | 0 | 1 |
   +-------+---+---+---+---+---+---+---+---+
```

**AND演算**

```c:BITOP_AND
// mybit1、mybit2、mybit3のキーのビットのANDを取ります
> bitop AND destbit mybit1 mybit2 mybit3
(integer) 1

// AND演算の結果です
> getbit destbit 0
(integer) 0
> getbit destbit 1
(integer) 0
> getbit destbit 2
(integer) 0
> getbit destbit 3
(integer) 0
> getbit destbit 4
(integer) 0
> getbit destbit 5
(integer) 0
> getbit destbit 6
(integer) 0
> getbit destbit 7
(integer) 0
```

**OR演算**

```c:BITOP_OR
// mybit1、mybit2、mybit3のキーのビットのORを取ります
> bitop OR destbit mybit1 mybit2 mybit3
(integer) 1

// OR演算の結果です
> getbit destbit 0
(integer) 0
> getbit destbit 1
(integer) 1
> getbit destbit 2
(integer) 1
> getbit destbit 3
(integer) 1
> getbit destbit 4
(integer) 1
> getbit destbit 5
(integer) 1
> getbit destbit 6
(integer) 1
> getbit destbit 7
(integer) 1
```

**XOR演算**

```c:BITOP_XOR
// mybit1、mybit2、mybit3のキーのビットのXORを取ります
> bitop XOR destbit mybit1 mybit2 mybit3
(integer) 1

// XOR演算の結果です
> getbit destbit 0
(integer) 0
> getbit destbit 1
(integer) 1
> getbit destbit 2
(integer) 1
> getbit destbit 3
(integer) 0
> getbit destbit 4
(integer) 1
> getbit destbit 5
(integer) 0
> getbit destbit 6
(integer) 0
> getbit destbit 7
(integer) 1
```

**NOT演算**

NOT演算のときは引数が異なり、指定できるキーは1つだけです。

```text:syntax
BITOP NOT destkey key
```

```c:BITOP_NOT
> setbit mybit 0 0
(integer) 0
> setbit mybit 1 1
(integer) 0
> setbit mybit 2 0
(integer) 0

// ビットを反転させます
> bitop NOT destbit mybit
(integer) 1

// NOT演算の結果です
> getbit destbit 0
(integer) 1
> getbit destbit 1
(integer) 0
> getbit destbit 2
(integer) 1
```

**参考**

> [redis command - strings] (http://redis.io/commands#string)

### ハッシュ

ハッシュ型の特徴

* 文字列のフィールドと文字列の値からなるマップです。
* 重複したフィールドを追加することはできません。
* 1つのハッシュが持てるフィールドと値のペアの最大数は2の32乗-1(4,294,967,295)です。

```text:hashes_image
> HSET myhash field1 "value1"
> HSET myhash field2 "value2"
> HSET myhash field3 "value3"

 +-[ key:myhash ]-------+
 |                      |
 |    field1 : value1   |
 |    field2 : value2   |
 |    field3 : value3   |
 +----------------------+
```

#### 基本操作

##### HSET / HSETNX / HGET

**フィールドと値の登録、取得を行います**

```text:syntax
HSET key field value
HSETNX key field value
HGET key field
```

`hset`コマンドでフィールドと値を登録し`hget`コマンドで値を取得します。
`hsetnx`コマンドは既存のフィールドに値を登録することはできません。(update不可)

```c:HSET
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1

> hget myhash1 fldstr
"abc"
```

```c:HSETNX
> hset myhash1 fldstr "abc"
(integer) 1

// すでに存在するフィールドには値を登録することはできません
> hsetnx myhash1 fldstr "def"
(integer) 0
> hget myhash1 fldstr
"abc"

// 新しいフィールドに対してのみ登録が可能です
> hsetnx myhash1 fldstr2 "def"
(integer) 1
> hget myhash1 fldstr2
"def"
```

##### HGETALL

**フィールドと値をすべて取得します**

```text:syntax
HGETALL key
```

```c:HGETALL
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1
> hset myhash1 fldflt "3.14"
(integer) 1

// フィールドと値の組み合わせで取得できます
> hgetall myhash1
1) "fldstr"
2) "abc"
3) "fldint"
4) "123"
5) "fldflt"
6) "3.14"
```

##### HDEL

**フィールドを削除します**

```text:syntax
HDEL key field [field ...]
```

```c:HDEL
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1
> hset myhash1 fldflt "3.14"
(integer) 1

// 削除したフィールドの件数が返ります
> hdel myhash1 fldstr fldint
(integer) 2

// 存在しないフィールドの場合は0が返ります
> hdel myhash1 fldxxx
(integer) 0

> hgetall myhash1
1) "fldflt"
2) "3.14"
```

##### HLEN

**フィールドの件数を取得します**

```text:syntax
HLEN key
```

```c:HLEN
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1
> hset myhash1 fldflt "3.14"
(integer) 1

> hlen myhash1
(integer) 3
```

##### HEXISTS

**フィールドの存在を確認します**

```text:syntax
HEXISTS key field
```

```c:HEXISTS
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1
> hset myhash1 fldflt "3.14"
(integer) 1

// 存在するフィールドは1が返ります
> hexists myhash1 fldstr
(integer) 1
// 存在しないフィールドは0が返ります
> hexists myhash1 fldxxx
(integer) 0
```

##### HKEYS / HVALS

**フィールド、値をすべて取得します**

```text:syntax
HKEYS key
HVALS key
```

```c:HKEYS_HVALS
> hset myhash1 fldstr "abc"
(integer) 1
> hset myhash1 fldint "123"
(integer) 1
> hset myhash1 fldflt "3.14"
(integer) 1

// フィールドをすべて取得できます
> hkeys myhash1
1) "fldstr"
2) "fldint"
3) "fldflt"

// 値をすべて取得できます。
> hvals myhash1
1) "abc"
2) "123"
3) "3.14"
```

#### マルチ操作

##### HMSET / HMGET

**一度に複数のフィールドと値を登録、取得を行います**

```text:syntax
HMSET key field value [field value ...]
HMGET key field [field ...]
```

```c:HMSET_HMGET
// フィールドと値のペアを複数指定してまとめて登録できます
> hmset myhash1 fldstr "abc" fldint "123" fldflt "3.14"
OK

// 指定したフィールドの値をまとめて取得します
> hmget myhash1 fldstr fldint fldflt
1) "abc"
2) "123"
3) "3.14"
```

#### インクリメント

##### HINCRBY

**incrementで指定した整数で値を加算します**

```text:syntax
HINCRBY key field increment
```

```c:HINCRBY
> hmset myhash1 fldstr "abc" fldint "123" fldflt "3.14"
OK

> hget myhash1 fldint
"123"

> hincrby myhash1 fldint 100
(integer) 223
```

##### HINCRBYFLOAT

**incrementで指定した浮動小数点数で値を加算します**

```text:syntax
HINCRBYFLOAT key field increment
```

```c:HINCRBYFLOAT
> hmset myhash1 fldstr "abc" fldint "123" fldflt "3.14"
OK

> hget myhash1 fldflt
"3.14"

> hincrbyfloat myhash1 fldflt "0.06"
"3.2"
```

**参考**

> [redis command - hash] (http://redis.io/commands#hash)

### セット

セット型の特徴

* 順番を持たない文字列(メンバー)の集合です。
* 重複したメンバーを登録することはできません。
* 1つのセットが持てるメンバーの最大数は2の32乗-1(4,294,967,295)です。

```text:sets_image
> SADD mysets member1
> SADD mysets member2
> SADD mysets member3

 +-[ key:mysets ]--------+
 |                       |
 |   member1             |
 |   member2             |
 |   member3             |
 +-----------------------+
```

#### 基本操作

##### SADD

**メンバーを追加します**

```text:syntax
SADD key member [member ...]
```

```c:SADD
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1

// すでに登録されているメンバーは0が返ります
> sadd myset1 "abc"
(integer) 0
```

##### SMEMBERS

**メンバーを取得します**

```text:syntax
SMEMBERS key
```

```c:SMEMBERS
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1

// 取得するメンバーの並びは不定です
> smembers myset1
1) "abc"
2) "def"
3) "ghi"
```

##### SCARD

**メンバーの件数を取得します**

```text:syntax
SCARD key
```

`SCARD`はSet CARDinalityの略のようです。

```c:SCARD
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1

> scard myset1
(integer) 3
```

##### SISMEMBER

**メンバーの存在を確認します**

```text:syntax
SISMEMBER key member
```

```c:SISMEMBER
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1

// 存在するメンバーは1が返ります
> sismember myset1 "abc"
(integer) 1
// 存在しないメンバーは0が返ります
> sismember myset1 "ABC"
(integer) 0
```

##### SREM

**メンバーを削除します**

```text:syntax
SREM key member [member ...]
```

```c:SREM
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1

> srem myset1 "abc"
(integer) 1
// 存在しないメンバーは0が返ります
> srem myset1 "abc"
(integer) 0

> smembers myset1
1) "def"
2) "ghi"
```

#### ランダム

##### SRANDMEMBER

**ランダムにメンバーを取得します**

```text:syntax
SRANDMEMBER key [count]
```

countに取得するメンバー数を指定します。

|count |description|
|:----:|:----------------------------------|
| > 0  |取得するメンバーに重複を許可しません。|
| < 0  |取得するメンバーに重複を許可します。  |

```c:SRANDMEMBER
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1
> sadd myset1 "123"
(integer) 1
> sadd myset1 "456"
(integer) 1

// 重複しないメンバーを3件取得します
> sramdmember myset1 3
1) "def"
2) "abc"
3) "456"

// countにマイナス値を指定するとメンバーが重複することがあります
> sradmember myset1 -6
1) "abc"
2) "456"
3) "ghi"
4) "ghi"
5) "456"
6) "123"
```

##### SPOP

**ランダムにメンバーを取得し且つ削除します**

```text:syntax
SPOP key [count]
```

:exclamation: [count]引数はバージョン2.6、2.8、3.0で利用できません。

> The count argument will be available in a later version and is not available in 2.6, 2.8, 3.0

`srandmember`はメンバーを更新しませんが`spop`はランダムに選んだメンバーを取得し且つ削除します。

```c:SPOP
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1
> sadd myset1 "123"
(integer) 1
> sadd myset1 "456"
(integer) 1

// ポップしたメンバーはキーから削除されます
> spop myste1
"ghi"

> smembers myset1
1) "def"
2) "abc"
3) "456"
4) "123"
```

#### セット間移動

**メンバーを別のキーへ移動します**

##### SMOVE

```text:syntax
SMOVE source destination member
```

```c:SMOVE
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1
> sadd myset1 "123"
(integer) 1
> sadd myset1 "456"
(integer) 1

// myset1の"abc"メンバーをmyset2へ移動します
> smove myset1 myset2 "abc"
(integer) 1

> smembers myset1
1) "123"
2) "ghi"
3) "def"
4) "456"
> smembers myset2
1) "abc"
```

存在しないキーへの移動もできます

```c:example
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1
> sadd myset1 "ghi"
(integer) 1

// myset2は存在しませんが移動させるとmyset2が作成され、そこへメンバーが移動します
> smove myset1 myset2 "abc"
(integer) 1

> smembers myset2
1) "abc"
```

#### 集合演算

**サンプルデータ**

```text:sample_image
> SADD myset1 "apple"
> SADD myset1 "orange"
> SADD myset1 "banana"
> SADD myset1 "peach"

> SADD myset2 "apple"
> SADD myset2 "banana"
> SADD myset2 "melon"

> SADD myset3 "apple"
> SADD myset3 "grape"
> SADD myset3 "peach"

               +--------+--------+--------+--------+--------+--------+
               | apple  | orange | banana | grape  | peach  | melon  |
      +--------+--------+--------+--------+--------+--------+--------+
      | myset1 |   o    |   o    |    o   |        |    o   |        |
      +--------+--------+--------+--------+--------+--------+--------+
      | myset2 |   o    |        |    o   |        |        |    o   |
      +--------+--------+--------+--------+--------+--------+--------+
      | myset3 |   o    |        |        |    o   |    o   |        |
      +--------+--------+--------+--------+--------+--------+--------+
```

##### SDIFF / SDIFFSTORE

**キーの差集合を求めます**

1番目に指定するキーのメンバーから2番目以降に指定するキーのメンバーを取り除いた結果を求めます。

```text:syntax
SDIFF key [key ...]
SDIFFSTORE destination key [key ...]
```

myset1とmyset2、myset3の差集合を求めます。
`SDIFFSTORE`は差集合の結果をdestinationで指定したキーに保存します

```c:SDIFF
> sadd myset1 "apple"
(integer) 1
> sadd myset1 "orange"
(integer) 1
> sadd myset1 "banana"
(integer) 1
> sadd myset1 "peach"
(integer) 1

> sadd myset2 "apple"
(integer) 1
> sadd myset2 "banana"
(integer) 1
> sadd myset2 "melon"
(integer) 1

> sadd myset3 "apple"
(integer) 1
> sadd myset3 "grape"
(integer) 1
> sadd myset3 "peach"
(integer) 1

> sdiff myset1 myset2 myset3
1) "orange"
```

##### SINTER / SINTERSTORE

**キーの積集合を求めます**

```text:syntax
SINTER key [key ...]
SINTERSTORE destination key [key ...]
```
myset1、myset2、myset3の積集合を求めます。
`SINTERSTORE`は積集合の結果をdestinationで指定したキーに保存します

```c:SINTER
> sadd myset1 "apple"
(integer) 1
> sadd myset1 "orange"
(integer) 1
> sadd myset1 "banana"
(integer) 1
> sadd myset1 "peach"
(integer) 1

> sadd myset2 "apple"
(integer) 1
> sadd myset2 "banana"
(integer) 1
> sadd myset2 "melon"
(integer) 1

> sadd myset3 "apple"
(integer) 1
> sadd myset3 "grape"
(integer) 1
> sadd myset3 "peach"
(integer) 1

> sinter myset1 myset2 myset3
1) "apple"
```

##### SUNION / SUNIONSTORE

**キーの和集合を求めます**

```text:syntax
SUNION key [key ...]
SUNIONSTORE destination key [key ...]
```

myset1、myset2、myset3の和集合を求めます。
`SUNIONSTORE `は和集合の結果をdestinationで指定したキーに保存します

```c:SUNION
> sadd myset1 "apple"
(integer) 1
> sadd myset1 "orange"
(integer) 1
> sadd myset1 "banana"
(integer) 1
> sadd myset1 "peach"
(integer) 1

> sadd myset2 "apple"
(integer) 1
> sadd myset2 "banana"
(integer) 1
> sadd myset2 "melon"
(integer) 1

> sadd myset3 "apple"
(integer) 1
> sadd myset3 "grape"
(integer) 1
> sadd myset3 "peach"
(integer) 1

> sunion myset1 myset2 myset3
1) "peach"
2) "orange"
3) "apple"
4) "banana"
5) "grape"
6) "melon"
```

**参考**

> [redis command - sets] (http://redis.io/commands#set)

### ソート済みセット

#### ソート済みセット型の特徴

* メンバーはスコアによって順位付けられた文字列(メンバー)の集合です。
* 重複したメンバーを登録することはできませんが、同じスコアを持つことはできます。
* 1つのソート済みセットが持てるメンバーの最大数は2の32乗-1(4,294,967,295)です。
* スコアは-2の53乗(-9,007,199,254,740,992)から2の53乗(9,007,199,254,740,992)です。

**スコア**

スコアはメンバーを追加する際に指定したり、インクリメントコマンドで増減させることができます。
コマンドにはスコアをmin,maxで指定するものがいくつかありますが、下記のような指定方法があります。

`1 10` は `1 <= score <= 10`という意味になります。

```c:example
> ZCOUNT myzset 1 10
```

`(1 (10` は `1 < score < 10`という意味になります。

```c:example
> ZCOUNT myzset (1 (10
```

`-inf +inf` は システムで表現できる最小値と最大値で全範囲を意味します。

```c:example
> ZCOUNT myzset -inf +inf
```

**ランク**

ランクはスコアによって決まり、直接指定することはできません。
また、スコアのソート順によってメンバーのランクは変わります。

スコアで昇順にソートした場合、スコアがもっとも少ないメンバーのランクは0になり、次が1、2と続きます。
逆に降順にソートした場合は、スコアがもっと多いメンバーのランクが0になり、次が1、2と続きます。

**インデックス**

ソートされたメンバーへはインデックスを指定してアクセスすることができます。
ランクと同じようにスコアのソート順によってメンバーのインデックスは変わります。

インデックスは、ソートされたメンバーを先頭からみた場合の「0から始まる正数のインデックス」と、末尾からみた場合の「-1から始まる負数のインデックス」があります。

**ソート済みセット型のデータイメージ**

```text:sorted_sets_image
> ZADD myzset 2 member1
> ZADD myzset 4 member2
> ZADD myzset 6 member3
> ZADD myzset 8 member4
> ZADD myzset -10 member5

   +-[ key:myzset ]----------------------------------------------------------+
   |                                                                         |
   |   +-------------+-------+-------+----------+-------+----------------+   |
   |   | member name | score | rank  | rev rank | index | negative index |   |
   |   +-------------+-------+-------+----------+-------+----------------+   |
   |   | member5     | -10   |  0    |   4      |  0    |  -5            |   |
   |   | member1     |  2    |  1    |   3      |  1    |  -4            |   |
   |   | member2     |  4    |  2    |   2      |  2    |  -3            |   |
   |   | member3     |  6    |  3    |   1      |  3    |  -2            |   |
   |   | member4     |  8    |  4    |   0      |  4    |  -1            |   |
   |   +-------------+-------+-------+----------+-------+----------------+   |
   |                                                                         |
   +-------------------------------------------------------------------------+

* rankは、scoreで昇順にソートしたときのランクです
* rev rankは、scoreで降順にソートしたときのランクです
* indexは、scoreで昇順にソートしたときの先頭から見たインデックスです
* negative indexは、scoreで昇順にソートしたときの末尾から見たインデックスです
```

#### 基本操作

##### ZADD / ZSCORE

**スコアを持つメンバーの追加やスコアの取得を行います**

```text:syntax
ZADD key score member [score member ...]
ZSCORE key member
```

```c:ZADD_ZSCORE
> zadd myzset1 2 member1
(integer) 1
> zadd myzset1 4 member2
(integer) 1
> zadd myzset1 6 member3
(integer) 1

// メンバーを複数指定してまとめて登録することができます
> zadd myzset1 8 member4 -10 member5
(integer) 2

// メンバーのスコアを取得します
> zscore myzset1 "member5"
"-10"

// zaddするメンバーが存在する場合、そのメンバーのスコアが更新されます
> zadd myzset1 -8 member5
(integer) 0
> zscore myzset1 member5
"-8"
```

##### ZCARD

**メンバーの件数を取得します**

```text:syntax
ZCARD key
```

```c:ZCARD
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

> zcard myzset1
(integer) 5
```

##### ZINCRBY

**メンバーのスコアを増減させます**

```text:syntax
ZINCRBY key increment member
```

```c:ZINCRBY
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// インクリメントした結果が返ります
> zincrby myzset1 1 member5
"-9"
> zincrby myzset1 1 member5
"-8"

// 存在しないメンバーをインクリメントすると、そのメンバーが追加されます
> zincrby myzset1 7 member6
"7"

// incrementにマイナス値を指定することもできます
> ZINCRBY myzset1 -1 "member5"
"-9"
```

##### ZREM

**メンバーを削除します**

```text:syntax
ZREM key member [member ...]
```

```c:ZREM
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

> zrem myzset1 member5
(integer) 1

> zcard myzset1
(integer) 4

// メンバーを複数指定してまとめて削除することができます
> zrem myzset1 member3 member4
(integer) 2
```

#### インデックスによる操作

##### ZRANGE / ZREVRANGE

**スコアでソートしたセットからインデックスで範囲を指定してメンバー(とスコア)を取得します**

```text:syntax
ZRANGE key start stop [WITHSCORES]
ZREVRANGE key start stop [WITHSCORES]
```

インデックスは

* ソートしたメンバーの先頭から見た場合、0から始まり1、2と続きます。
* ソートしたメンバーの末尾から見た場合、-1から始まり-2、-3と続きます。

`ZRANGE`はスコアで昇順にソートします。
start、endにはインデックスを指定します。withscoresを指定するとスコアも表示します。

```c:ZRANGE
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// インデックス0番目から2番目のメンバーを取得します
> zrange myzset1 0 2
1) "member5"
2) "member1"
3) "member2"

// インデックス0番目のメンバーとスコアを取得します
> zrange myzset1 0 0 withscores
 1) "member5"
 2) "-10"

// インデックスに0から-1を指定するとすべてのメンバーとスコアを取得します
> zrange myzset1 0 -1 withscores
 1) "member5"
 2) "-10"
 3) "member1"
 4) "2"
 5) "member2"
 6) "4"
 7) "member3"
 8) "6"
 9) "member4"
10) "8"
```

`ZREVRANGE`はスコアで降順にソートします。

```c:ZREVRANGE
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// スコアの高い順にメンバーを取得します。
> zrevrange myzset1 0 -1 withscores
 1) "member4"
 2) "8"
 3) "member3"
 4) "6"
 5) "member2"
 6) "4"
 7) "member1"
 8) "2"
 9) "member5"
10) "-10"
```

#### スコアに関する操作

##### ZCOUNT

**スコアで範囲を指定してメンバーの件数を取得します**

```text:syntax
ZCOUNT key min max
```

min,maxにはスコアを指定します。具体的なスコアの代わりに`-inf`、`+inf`を指定することも可能です。

```c:ZCOUNT
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// スコアが2以上10以下(2 <= score <= 10)のメンバーの件数を取得します
> zcount myzset1 2 10
(integer) 4

// スコアが2より大きく10より小さい(2 < score < 10)のメンバーの件数を取得します
> zcount myzset1 (2 (10
(integer) 3

// すべてのメンバーの件数を取得します
> zcount myzset1 -inf +inf
(integer) 5
```

##### ZRANGEBYSCORE / ZREVRANGEBYSCORE

**スコアで範囲を指定してメンバー(とスコア)を取得します**

```text:syntax
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count]
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count]
```

min,maxにはスコアを指定します。具体的なスコアの代わりに`-inf`、`+inf`を指定することも可能です。
取得件数を制限したい場合は、offsetにはインデックス、countには取得する件数を指定します。

`ZRANGEBYSCORE`はスコアで昇順にソートします。

```c:ZRANGEBYSCORE
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// すべてのメンバーとスコアを取得します
> zrangebyscore myzset1 -inf +inf withscores
 1) "member5"
 2) "-10"
 3) "member1"
 4) "2"
 5) "member2"
 6) "4"
 7) "member3"
 8) "6"
 9) "member4"
10) "8"

// 先頭から3件のメンバーとスコアを取得します
> zrangebyscore myzset1 -inf +inf withscores limit 0 3
1) "member5"
2) "-10"
3) "member1"
4) "2"
5) "member2"
6) "4"
```

`ZREVRANGEBYSCORE`はスコアで降順にソートします。

```c:ZREVRANGEBYSCORE
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// すべてのメンバーとスコアを取得します
> zrevrangebyscore myzset1 +inf -inf withscores
 1) "member4"
 2) "8"
 3) "member3"
 4) "6"
 5) "member2"
 6) "4"
 7) "member1"
 8) "2"
 9) "member5"
10) "-10"
```

##### ZREMRANGEBYSCORE

**スコアで範囲を指定してメンバーを削除します**

```text:syntax
ZREMRANGEBYSCORE key min max
```

min,maxにはスコアを指定します。具体的なスコアの代わりに`-inf`、`+inf`を指定することも可能です。

```c:ZREMRANGEBYSCORE
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// すべて削除します。(これはdel myzset1と同じです)
> zremrangebyscore myzset1 -inf +inf
(integer) 5

> zcard myzset1
(integer) 0
```

#### ランクに関する操作

##### ZRANK / ZXREVRANK

**メンバーのランクを取得します**

```text:syntax
ZRANK key member
ZREVRANK key member
```

`ZRANK`はスコアで昇順にソートしたときのランクを取得します。もっともスコアが少ないメンバーがランク0になります。

```c:ZRANK
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// スコアを昇順にソートしたときのmember5のランクを取得します
> zrank myzset1 member5
(integer) 0

// スコアを昇順にソートしたときのmember4のランクを取得します
> zrank myzset1 member4
(integer) 4
```

`ZREVRANK`はスコアで降順にソートしたときのランクを取得します。もっともスコアが多いメンバーがランク0になります。

```c:ZREVRANK
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// スコアを降順にソートしたときのmember5のランクを取得します
> zrevrank myzset1 member5
(integer) 4

// スコアを降順にソートしたときのmember4のランクを取得します
> zrevrank myzset1 member4
(integer) 0
```

##### ZREMRANGEBYRANK

**ランクで範囲を指定してメンバーを削除します**

```text:syntax
ZREMRANGEBYRANK key start stop
```

スコアで昇順にソートした場合のランクで範囲を指定してメンバーを削除します。

```c:ZREMRANGEBYRANK
> zadd myzset1 2 member1 4 member2 6 member3 8 member4 -10 member5
(integer) 5

// メンバーのランクを確認します
> zrank myzset1 member1
(integer) 1
> zrank myzset1 member2
(integer) 2
> zrank myzset1 member3
(integer) 3
> zrank myzset1 member4
(integer) 4
> zrank myzset1 member5
(integer) 0

// ランクが0から2のメンバーを削除します
> zremrangebyrank myzset1 0 2
(integer) 3

// 残ったメンバーを確認します
> zrange myzset1 0 -1 withscores
1) "member3"
2) "6"
3) "member4"
4) "8"
```

#### 集合演算

**サンプルデータ**

```text:sample_image
> ZADD myzset1 1 "apple"
> ZADD myzset1 2 "orange"
> ZADD myzset1 3 "banana"
> ZADD myzset1 5 "peach"

> ZADD myzset2 3 "apple"
> ZADD myzset2 4 "orange"
> ZADD myzset2 7 "banana"
> ZADD myzset2 4 "grape"
> ZADD myzset2 9 "peach"

> ZADD myzset3 5 "apple"
> ZADD myzset3 5 "banana"
> ZADD myzset3 6 "grape"
> ZADD myzset3 7 "peach"
> ZADD myzset3 6 "melon"

                +--------+--------+--------+--------+--------+--------+
                | apple  | orange | banana | grape  | peach  | melon  |
      +---------+--------+--------+--------+--------+--------+--------+
      | myzset1 |   1    |   2    |    3   |        |    5   |        |
      +---------+--------+--------+--------+--------+--------+--------+
      | myzset2 |   3    |   4    |    7   |    4   |    9   |        |
      +---------+--------+--------+--------+--------+--------+--------+
      | myzset3 |   5    |        |    5   |    6   |    7   |    6   |
      +---------+--------+--------+--------+--------+--------+--------+

演算結果

ZINTERSTORE
                +--------+--------+--------+--------+--------+--------+
                | apple  | orange | banana | grape  | peach  | melon  |
      +---------+--------+--------+--------+--------+--------+--------+
      | SUM     |   9    |        |   15   |        |   21   |        |
      +---------+--------+--------+--------+--------+--------+--------+
      | MIN     |   1    |        |    3   |        |    5   |        |
      +---------+--------+--------+--------+--------+--------+--------+
      | MAX     |   5    |        |    7   |        |    9   |        |
      +---------+--------+--------+--------+--------+--------+--------+

ZUNIONSTORE
                +--------+--------+--------+--------+--------+--------+
                | apple  | orange | banana | grape  | peach  | melon  |
      +---------+--------+--------+--------+--------+--------+--------+
      | SUM     |   9    |    6   |   15   |   10   |   21   |    6   |
      +---------+--------+--------+--------+--------+--------+--------+
      | MIN     |   1    |    2   |    3   |    4   |    5   |    6   |
      +---------+--------+--------+--------+--------+--------+--------+
      | MAX     |   5    |    4   |    7   |    6   |    9   |    6   |
      +---------+--------+--------+--------+--------+--------+--------+

```

##### ZINTERSTORE

**メンバーの積集合を求めます**

```text:syntax
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
```

numkeysには、演算するソート済みセットの数を指定します。
weightsには、各キーのスコアに適用する重みを指定します。デフォルトは1で、例えば2を指定すればスコアを2倍します。
aggregateには、各キーのスコアの集約方法を指定します。デフォルトはsumで各キーのスコアを合計します。

```c:ZINTERSTORE
> zinterstore destzset 3 myzset1 myzset2 myzset3
(integer) 3

> zrange destzset 0 -1 withscores
1) "apple"
2) "9"
3) "banana"
4) "15"
5) "peach"
6) "21"
```

##### ZUNIONSTORE

**メンバーの和集合を求めます**

```text:syntax
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX]
```

```c:ZUNIONSTORE
> zunionstore destzset 3 myzset1 myzset2 myzset3
(integer) 6

> zrange destzset 0 -1 withscores
 1) "melon"
 2) "6"
 3) "orange"
 4) "6"
 5) "apple"
 6) "9"
 7) "grape"
 8) "10"
 9) "banana"
10) "15"
11) "peach"
12) "21"
```

**参考**

> [redis command - sorted sets] (http://redis.io/commands#sorted_set)

### リスト

リスト型の特徴

* 挿入した順番を保持する文字列のリストです。
* 同じ文字列を挿入することができます。
* リストの先頭(Left)または末尾(Right)から値を挿入および取り出しを行うことができます。
* 1つのリストが持てる値の最大数は2の32乗-1(4,294,967,295)です。

**リスト型のデータイメージ**

インデックス

* 上側の正数はリストの先頭(Left)側から数えたインデックスで0から始まり1、2と続きます。
* 下側の負数はリストの末尾(Right)側から数えたインデックスで-1から始まり、-2、-3と続きます。

```text:lists_image
> LPUSH fruits "apple"
> LPUSH fruits "orange"
> LPUSH fruits "banana"
> LPUSH fruits "melon"

 +-[ key:fruits ]---------------------------------+
 |                                                |
 | (L)  0        1        2        3  　          |
 |     +--------+--------+--------+--------+      |
 |     | melon  | banana | orange | apple  |      |
 |     +--------+--------+--------+--------+      |
 |         　 -4       -3       -2       -1  (R)  |
 +------------------------------------------------+
```

#### 基本操作

##### LPUSH / LPUSHX

**リストの先頭(Left)に値を挿入します**

```text:syntax
LPUSH key value [value ...]
LPUSHX key value
```

```c:LPUSH
> lpush mylist1 "abc"
(integer) 1
> lpush mylist1 "def"
(integer) 2
> lpush mylist1 "ghi"
(integer) 3

// 同じ値を追加することができます。（重複を許可します）
> lpush mylist1 "abc"
(integer) 4
```

`LPUSHX`はキーが存在しない場合、何も行いません。

```c:LPUSHX
> del mylist1
(integer) 0

// 存在しないキーに値を追加することはできません
> lpushx mylist1 "abc"
(integer) 0
```

##### LPOP

**リストの先頭(Left)から値を取り出します**

```text:syntax
LPOP key
```

```c:LPOP
> lpush mylist1 "abc"
(integer) 1
> lpush mylist1 "def"
(integer) 2
> lpush mylist1 "ghi"
(integer) 3
> lpush mylist1 "abc"
(integer) 4

> lrange mylist1 0 -1
1) "abc"
2) "ghi"
3) "def"
4) "abc"

> lpop mylist1
"abc"

> lrange mylist1 0 -1
1) "ghi"
2) "def"
3) "abc"
```

##### RPUSH / RPUSHX

**リストの末尾(Right)に値を挿入します**

`RPUSHX`はキーが存在しない場合、何も行いません。

```text:syntax
RPUSH key value [value ...]
RPUSHX key value
```

```c:RPUSH
> rpush mylist2 "abc"
(integer) 1
> rpush mylist2 "def"
(integer) 2
> rpush mylist2 "ghi"
(integer) 3
> rpush mylist2 "abc"
(integer) 4

> lrange mylist2 0 -1
1) "abc"
2) "def"
3) "ghi"
4) "abc"
```

##### RPOP

**リストの末尾(Right)から値を取り出します**

```text:syntax
RPOP key
```

```c:RPOP
> rpush mylist2 "abc"
(integer) 1
> rpush mylist2 "def"
(integer) 2
> rpush mylist2 "ghi"
(integer) 3
> rpush mylist2 "abc"
(integer) 4

> lrange mylist2 0 -1
1) "abc"
2) "def"
3) "ghi"
4) "abc"

> rpop mylist2
"abc"

> lrange mylist2 0 -1
1) "abc"
2) "def"
3) "ghi"
```

##### LLEN

**リストの長さを取得します**

```text:syntax
LLEN key
```

```c:LLEN
> lpush mylist1 "abc"
(integer) 1
> lpush mylist1 "def"
(integer) 2
> lpush mylist1 "ghi"
(integer) 3
> lpush mylist1 "abc"
(integer) 4

> llen mylist1
(integer) 4
```

##### LREM

**リストから指定した値を削除します**

```text:syntax
LREM key count value
```

|count |desc    |
|:-----|:-------|
| > 0  |リストの先頭(Left)からvalueで指定した値をcountで指定した件数だけ削除  |
| < 0  |リストの末尾(Right)からvalueで指定した値をcountで指定した件数だけ削除  |
| = 0  |リスト全体からvalueで指定した値をすべて削除  |


**サンプルデータ**

```text:sample_data_image
> LPUSH mylist3 apple
> LPUSH mylist3 orange
> LPUSH mylist3 banana
> LPUSH mylist3 apple
> LPUSH mylist3 orange
> LPUSH mylist3 peach
> LPUSH mylist3 melon
> LPUSH mylist3 apple

 +-[ key:mylist3 ]--------------------------------------------------------------------+
 |                                                                                    |
 | (L)  0        1        2        3  　    4        5        6        7              |
 |     +--------+--------+--------+--------+--------+--------+--------+--------+      |
 |     | apple  | melon  | peach  | orange | apple  | banana | orange | apple  |      |
 |     +--------+--------+--------+--------+--------+--------+--------+--------+      |
 |            -8       -7       -6       -5    　 -4       -3       -2       -1  (R)  |
 +------------------------------------------------------------------------------------+
```

countに0以上の正数を指定した場合、リストの先頭(Left)よりvalueと一致する値をcount数分削除します。

```c:LREM
> lrange mylist3 0 -1
1) "apple"
2) "melon"
3) "peach"
4) "orange"
5) "apple"
6) "banana"
7) "orange"
8) "apple"

> lrem mylist3 2 "apple"
(integer) 2

> lrange mylist3 0 -1
1) "melon"
2) "peach"
3) "orange"
4) "banana"
5) "orange"
6) "apple"
```

countに負数を指定した場合、リストの末尾(Right)よりvalueと一致する値をcount数分削除します。

```c:LREM
> lrange mylist3 0 -1
1) "apple"
2) "melon"
3) "peach"
4) "orange"
5) "apple"
6) "banana"
7) "orange"
8) "apple"

> lrem mylist3 -2 "apple"
(integer) 2

> lrange mylist3 0 -1
1) "apple"
2) "melon"
3) "peach"
4) "orange"
5) "banana"
6) "orange"
```

countに0を指定した場合、リスト全体からvalueで指定した値をすべて削除します。

```c:LREM
> lrange mylist3 0 -1
1) "melon"
2) "peach"
3) "orange"
4) "apple"
5) "banana"
6) "orange"
7) "apple"

> lrem mylist3 0 "apple"
(integer) 2

> lrange mylist3 0 -1
1) "melon"
2) "peach"
3) "orange"
4) "banana"
5) "orange"
```

##### LINSERT

**リストの指定した位置へ新しい値を追加します**

```text:syntax
LINSERT key BEFORE|AFTER pivot value
```

pivotで指定する値の前後どちらかにvalueで指定する値を追加します。

```c:LINSERT
> lpush mylist "apple"
(integer) 1
> lpush mylist "orange"
(integer) 2
> lpush mylist "banana"
(integer) 3
> lpush mylist "apple"
(integer) 4
> lpush mylist "orange"
(integer) 5
> lpush mylist "peach"
(integer) 6
> lpush mylist "melon"
(integer) 7
> lpush mylist "apple"
(integer) 8

> lrange mylist 0 -1
1) "apple"
2) "melon"
3) "peach"
4) "orange"
5) "apple"
6) "banana"
7) "orange"
8) "apple"

> linsert mylist after "orange" "ringo"
(integer) 9

> lrange mylist 0 -1
1) "apple"
2) "melon"
3) "peach"
4) "orange"
5) "ringo"
6) "apple"
7) "banana"
8) "orange"
9) "apple"
```

pivotで指定する値がリスト内に複数あった場合、先頭(Left)からみて最初に見つかった値が選ばれるようです。

#### インデックスによる操作

##### LINDEX

**インデックスで指定した値を取得します**

```text:syntax
LINDEX key index
```

**インデックス**

* リストの先頭(Left)から見た場合、0から始まり1、2と続きます。
* リストの末尾(Right)から見た場合、-1から始まり-2、-3と続きます。

**サンプルデータ**

```c:list_sample_data
> lpush mylist "apple"
> lpush mylist "orange"
> lpush mylist "banana"
> lpush mylist "apple"
> lpush mylist "orange"

 +-[ key:mylist ]------------------------------------------+
 |                                                         |
 | (L)  0        1        2        3        4              |
 |     +--------+--------+--------+--------+--------+      |
 |     | orange | apple  | banana | orange | apple  |      |
 |     +--------+--------+--------+--------+--------+      |
 |            -5       -4       -3       -2       -1  (R)  |
 +---------------------------------------------------------+
```

```c:LINDEX
> lrange mylist 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"
5) "apple"

> lindex mylist 0
"orange"
> lindex mylist 1
"apple"
> lindex mylist 2
"banana"
> lindex mylist 3
"orange"
> lindex mylist 4
"apple"
> lindex mylist 5
(nil)
> lindex mylist -1
"apple"
```

##### LRANGE

**インデックスで指定した範囲の値を取得します**

```text:syntax
LRANGE key start stop
```
start,stopにはインデックスを指定をします。
この例ではstartに0、stopに-1を指定してリスト全体の値を取得しています。

```c:LRANGE
> lpush mylist "apple"
(integer) 1
> lpush mylist "orange"
(integer) 2
> lpush mylist "banana"
(integer) 3
> lpush mylist "apple"
(integer) 4
> lpush mylist "orange"
(integer) 5

> lrange mylist 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"
5) "apple"
```

##### LSET

**インデックスで指定した位置の値を上書きします**

```text:syntax
LSET key index value
```

```c:LSET
> lpush mylist "apple"
(integer) 1
> lpush mylist "orange"
(integer) 2
> lpush mylist "banana"
(integer) 3
> lpush mylist "apple"
(integer) 4
> lpush mylist "orange"
(integer) 5

> lrange mylist 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"
5) "apple"

> lset mylist 3 "ringo"
OK

> lrange mylist 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "ringo"
5) "apple"
```

##### LTRIM

**インデックスで指定した範囲の値にトリムします**

```text:syntax
LTRIM key start stop
```

start,stopにはインデックスを指定をします。
この例では2番目から4番目の値を持つリストへトリムします。

```c:LTRIM
> lpush mylist "apple"
(integer) 1
> lpush mylist "orange"
(integer) 2
> lpush mylist "banana"
(integer) 3
> lpush mylist "apple"
(integer) 4
> lpush mylist "orange"
(integer) 5

> lrange mylist 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"
5) "apple"

> ltrin mylist 1 3
OK

> lrange mylist 0 -1
1) "apple"
2) "banana"
3) "orange"
```

#### リスト間移動

##### RPOPLPUSH

**値を別のリストへ移動させます**

```text:syntax
RPOPLPUSH source destination
```

リストの末尾(Right)から別のリストの先頭(Left)へ値を移動させます。

```c:RPOPLPUSH
> lpush mylist1 "apple"
(integer) 1
> lpush mylist1 "orange"
(integer) 2
> lpush mylist1 "banana"
(integer) 3
> lpush mylist1 "apple"
(integer) 4
> lpush mylist1 "orange"
(integer) 5

> lrange mylist1 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"
5) "apple"

> lrange mylist2 0 -1
(empty list or set)

> rpoplpush mylist1 mylist2
"apple"

> lrange mylist1 0 -1
1) "orange"
2) "apple"
3) "banana"
4) "orange"

> lrange mylist2 0 -1
1) "apple"
```

#### ブロッキング

##### BLPOP / BRPOP

**リストから値を取得するまでブロックします**

```text:syntax
BLPOP key [key ...] timeout
BRPOP key [key ...] timeout
```

timeout

* 0を指定すると値を取得するまで無期限にブロックします。
* 正数を指定すると値を取得するまでブロックする最大秒数として扱われます。

Client A側でmylist1、mylist2のどちらかから値を取得するためブロックします。

```c:BLPOP_ClientA
> blpop mylist1 mylist2 0

//どちらかのリストから要素を取得できるまでブロック
```

Client B側でmylist1へ値をプッシュします。

```c:BLPOP_Client_B
> lpush mylist1 "abc"
(integer) 1
```

Client A側ではmylist1から値を取得しブロックを解除します。

```c:BLPOP_Client_A
1) "mylist1"
2) "abc"
(66.44s)
```

timeoutに秒数を指定した場合、指定秒数内に値が取得できなければタイムアウトします。

```c:example
> blpop mylist1 mylist2 30

//30経過
(nil)
(30.57s)
```

##### BRPOPLPUSH

**値を別のリストへ移動させるまでブロックします**

```text:syntax
BRPOPLPUSH source destination timeout
```

Client A側でmylist1から値を取得しmylist2へ値を移動させるまでブロックします。

```c:BRPOPLPUSH_ClientA
> brpoplpush mylist1 mylist2 0

//mylist1から値を取得できるまでブロック
```

Client B側でmylist1へ値をプッシュします。

```c:BRPOPLPUSH_ClientB
> lpush mylist1 "abc"
(integer) 1
```

Client A側ではmylist1から値を取得しmylist2へ移動させてブロックを解除します。

```c:BRPOPLPUSH_ClientA
"abc"
(13.37s)
> lrange mylist2 0 -1
1) "abc"
```

**参考**

> [redis commands - Lists] (http://redis.io/commands#list)

### キー

#### 基本操作

##### EXISTS

**キーの存在を確認します**

```text:syntax
EXISTS key
```

```c:EXISTS
> set mykey1 "abc"
OK

> exists mykey1
(integer) 1
> exists mykey2
(integer) 0
```

##### TYPE

**データタイプを確認します**

```text:syntax
TYPE key
```

```c:TYPE
> set mykey1 "abc"
OK
> set mykey2 "123"
OK
> lpush mylist "abc"
(integer) 1
> hset myhash abc "def"
(integer) 1
> sadd myset1 "abc"
(integer) 1
> zadd myzset1 0 "abc"
(integer) 1

> type mykey1
string
> type mykey2
string
> type mylist
list
> type myset
set
> type myzset
zset
> type myhash
hash
```

##### RENAME / RENAMENX

**キーの名前を変更します**

```text:syntax
RENAME key newkey
RENAMENX key newkey
```

```c:RENAME
> set mykey1 "abc"
OK
> set mykey2 "def"
OK

// 変更先のキーが存在している場合は上書きします
> rename mykey1 mykey2
OK

> get mykey1
(nil)
> get mykey2
"abc"
```

`renamenx`では変更先の名前が既に使用されている場合は名前の変更ができません。

```C:RENAMENX
> set mykey1 "abc"
OK
> set mykey2 "def"
OK

// 変更先のキーが存在する場合は変更できません
> renamenx mykey1 mykey2
(integer) 0
```

##### DEL

**キーを削除します**

```text:syntax
DEL key [key ...]
```

```c:DEL
> set mykey1 "abc"
OK
> del mykey1
(integer) 1
> get mykey1
(nil)
```

#### 期限に関する操作

##### EXPIRE / EXPIREAT / TTL

**キーに有効期限(秒単位)を設定します**

```text:syntax
EXPIRE key seconds
EXPIREAT key timestamp
TTL key
```

`ttl`コマンドはキーの有効期限を確認することができます。
返り値がマイナスの場合は以下の意味にます。

* -2: キーは存在しません。
* -1: キーには有効期限が設定されていません。

```c:EXPIRE
> set mykey1 "abc"
OK

// 有効期限が設定されていないキーは-1を返します
> ttl mykey1
(integer) -1

// 有効期限を10秒に設定します
> expire mykey1 10
(integer) 1

// 有効期限がある場合、残りの期限を表示します
> ttl mykey1
(integer) 7

//暫く待ちます

// キーが存在しない場合は-2が返ります
> ttl mykey1
(integer) -2
> get mykey1
(nil)
```

`expireat`コマンドは有効期限をUnix Timestampで指定します。

```c:EXPIREAT
> set mykey1 abc
OK

> ttl mykey1
(integer) -1

> expireat mykey1 1432085880
(integer) 1
> ttl mykey1
(integer) 40

//暫く待ちます

> ttl mykey1
(integer) -2
> get mykey1
(nil)
```

#####  PEXPIRE / PEXPIREAT / PTTL

**キーに有効期限(ミリ秒単位)を設定します**

```c:syntax
PEXPIRE key milliseconds
PEXPIREAT key milliseconds-timestamp
PTTL key
```

```c:PEXPIRE
> set mykey1 "abc"
OK

> pttl mykey1
(integer) -1

> expire mykey1 10000
(integer) 1

> pttl mykey1
(integer) 6634

//暫く待ちます

> pttl mykey1
(integer) -2
> get mykey1
(nil)
```

##### PERSIST

**キーから有効期限を取り除きます**

```text:syntax
PERSIST key
```

```c:PERSIST
> set mykey1 "abc"
OK

> expire mykey1 30
(integer) 1

> ttl mykey1
(integer) 27

// 有効期限を取り除きます
> persist mykey1
(integer) 1

> ttl mykey1
(integer) -1
```

#### ランダム

##### RANDOMKEY

**現在のデータベースからランダムに選択したキーを返します**

```text:syntax
RANDOMKEY
```

```c:RANDOMKEY
> mset mykey1 "abc" mykey2 "def" mykey3 "ghi" mykey4 "jkl"
OK

> keys *
1) "mykey2"
2) "mykey4"
3) "mykey3"
4) "mykey1"

// ランダムにキーを取得します
> randomkey
"mykey2"
> randomkey
"mykey3"
> randomkey
"mykey2"
```

#### ダンプ＆リストア

##### DUMP

**キーの値をシリアライズしたデータにして返します**

キーに有効期限を設定していてもその情報は含まれません。

```text:syntax
DUMP key
```

```c:DUMP
> set mykey1 "abc"
OK

> dump mykey1
"\x00\x03abc\x06\x00OAX\xbd\xb4'\x9eq"
```

##### RESTORE

**DUMPコマンドでシリアライズしたデータをキーの値へ復元します**

```text:syntax
RESTORE key ttl serialized-value [REPLACE]
```

**文字列**

```c:RESTORE_strings
> set mykey1 "abc"
OK

> dump mykey1
"\x00\x03abc\x06\x00OAX\xbd\xb4'\x9eq"

// mykey2へリストアします
> restore mykey2 0 "\x00\x03abc\x06\x00OAX\xbd\xb4'\x9eq"
OK

> get mykey2
"abc"
```

**リスト**

```c:RESTORE_lists
> lpush mylist1 "abc"
(integer) 1
> lpush mylist1 "def"
(integer) 2
> lpush mylist1 "ghi"
(integer) 3

> dump mylist1
"\n\x1a\x1a\x00\x00\x00\x14\x00\x00\x00\x03\x00\x00\x03ghi\x05\x03def\x05\x03abc\xff\x06\x00W\x0bW\xae{\x9b\xd1e"

> restore mylist2 0 "\n\x1a\x1a\x00\x00\x00\x14\x00\x00\x00\x03\x00\x00\x03ghi\x05\x03def\x05\x03abc\xff\x06\x00W\x0bW\xae{\x9b\xd1e"
OK

> lrange mylist2 0 -1
1) "ghi"
2) "def"
3) "abc"
```

:exclamation: [Restore](http://redis.io/commands/restore)ではREPLACEオプションの記述がありますが、windows版のredis2.8.19ではREPLACEオプションは使用できないようです。

```bash:command_help
127.0.0.1:6379> help restore

  RESTORE key ttl serialized-value
  summary: Create a key using the provided serialized value, previously obtained using DUMP.
  since: 2.6.0
  group: generic
```

#### その他

##### KEYS

**検索するパターンに一致するキーを取得します**

```text:syntax
KEYS pattern
```

```c:KEYS
> mset mykey1 "abc" mykey2 "def" mykey3 "ghi" mykey4 "jkl" mykey5 "mno"
OK
> hset myhash1 "f1" "v1"
(integer) 1
> hset myhash2 "f2" "v1"
(integer) 1
> lpush mylist1 "abc"
(integer) 1

// 名前がmykeyから始まるキーを検索します
> keys mykey*
1) "mykey2"
2) "mykey5"
3) "mykey1"
4) "mykey3"
5) "mykey4"

// 名前がmykey1、mykey2、mykey3のキーを検索します
> keys mykey[1-3]
1) "mykey2"
2) "mykey1"
3) "mykey3"
```

***Supported glob-style patterns***

|meta|description           |
|:---|:---------------------|
|*   |0以上の文字とのマッチ   |
|?   |ただ一つの文字とのマッチ|
|[ ] |文字集合/範囲          |

:exclamation: 大規模データベースではパフォーマンスを低下させることがあるので本番環境での使用には注意が必要

##### MOVE

**キーを別のデータベースへ移動します**

```text:syntax
MOVE key db
```

データベースは0から始まる数値で指定します。デフォルトは0です。
この例では、0番のデータベースで登録したキーを1番のデータベースへ移動させます。

```c:MOVE
// DB0番にmykey1を登録します
> select 0
OK
> set mykey1 "abc"
OK

// DB1へキーを移動させます
> move mykey1 1
(integer) 1

// DB1へ移動してキーを確認します
> select 1
OK
[1]> get mykey1
"abc"
```

使用できるdatabaseの数は、redis.confの`databases`で指定します。

##### OBJECT

**キーに関連付けられたRedisオブジェクトの内部情報を取得します**

```text:syntax
OBJECT subcommand [arguments [arguments ...]]
```

```c:OBJECT
> set mykey1 "abc"
OK

> object refcount mykey1
(integer) 1
> object encoding mykey1
"raw"
> object idletime mykey1
(integer) 22
```

***subcommand***

|subcommand|return |description             |
|:---------|:------|:-----------------------|
|REFCOUNT  |Integer|値への参照数を取得 (どのような時に必要な情報か分かりませんでした。)|
|ENCODING  |String |値のエンコードの種類を取得 |
|IDLETIME  |Integer|値のアイドル秒数を取得     |

***encode***

|data type  |encoding                 |description                              |
|:----------|:------------------------|:----------------------------------------|
|strings    |<ul><li>raw</li><li>int</li></ul>           |intは64ビット符号付整数として表現できる場合に使用される |
|lists      |<ul><li>ziplist</li><li>linkedlist</li></ul>|ziplistは小さなリストに使用される           |
|hashes     |<ul><li>zipmap</li><li>hashtable</li></ul>  |zipmapは小さなハッシュに使用される          |
|sets       |<ul><li>intset</li><li>hashtable</li></ul>  |intsetは正数の小さなセットに使用される       |
|sorted sets|<ul><li>ziplist</li><li>skiplist</li></ul>  |skiplistは小さなソート済みセットに使用される |

**文字列型**

```c:OBJECT_strings
> del mykey1
(integer) 0
> del mykey2
(integer) 0

> set mykey1 "abc"
OK
> object encoding mykey1
"raw"

> set mykey2 123
OK
> object encoding mykey2
"int"
```

**リスト型**

```c:OBJECT_lists
> del mylist1
(integer) 0

> lpush mylist1 "abc"
(integer) 1
> lpush mylist1 "def"
(integer) 2
> lpush mylist1 "ghi"
(integer) 3

> object encoding mylist1
"ziplist"
```

**ハッシュ型**

```c:OBJECT_hashes
> hset myhash1 "f1" "v1"
(integer) 1
> hset myhash1 "f2" "v2"
(integer) 1
> hset myhash1 "f3" "v3"
(integer) 1

> object encoding myhash1
"ziplist"
```

**セット型**

```c:OBUJECT_sets
> sadd myset1 "abc"
(integer) 1
> sadd myset1 "def"
(integer) 1

> object encoding myset1
"hashtable"
```

**セット型（整数）**

```c:OBJECT_sets
> sadd myset2 "123"
(integer) 1
> sadd myset2 "456"
(integer) 1
> sadd myset2 "789"
(integer) 1

> object encoding myset2
"intset"
```

**参考**

> [redis commands - keys] (http://redis.io/commands#generic)