MongoDB 3.2 のドキュメントバリデーション機能説明

MongoDB 3.2 になって、ドキュメントバリデーション機能が追加されましたので、説明します。

## コレクションを作る時に、バリデーションをかける方法

例えばhogeコレクションのnameというキーの値を文字列に限定したい場合は、以下の様にします。

```
> db.createCollection( "user" , {
    validator : { 
         name : { $type : "string" },
         age : { $gt : "number" }
    },
    validationLevel: "strict", # ←省略可
    validationAction: "error" # ←省略可
  })
```

そうすると、正しいドキュメントは入りますが、

```
> db.user.insert({"name":"fetaro","age":33})
WriteResult({ "nInserted" : 1 })
```

以下の様にnameに数字を入れると怒られます。エラーメッセージは"Document failed validation"で固定です。

```
> db.user.insert({"name":1,"age":1})
WriteResult({
        "nInserted" : 0,
        "writeError" : {
                "code" : 121,
                "errmsg" : "Document failed validation"
        }
})
```

## バリデーションの変更

バリデーションを変更したり、既存のコレクションにバリデーションを後からかける場合は、runCommandを使います（たぶんこれしか方法が無い)

```
db.runCommand({
   "collMod" : "user" , 
   "validator" :  { 
      name : { $type : "string" },
      age : { $gt : 0 }
  } } )
```

## バリデーションの確認

バリデーションの定義はdb.getCollectionInfos()をたたくと見れます。かなり大雑把なつくりです。。。

```
> db.getCollectionInfos()
[
       {
                "name" : "user",
                "options" : {
                        "validator" : {
                                "name" : {
                                        "$type" : "string"
                                },
                                "age" : {
                                        "$gt" : 0
                                }
                        },
                        "validationLevel" : "strict",
                        "validationAction" : "error"
                }
        }
]
```

## バリデーションの内容 (validator)

バリデーションの内容の定義は、find()などで条件を指定するときに使う表現がほぼそのまま使えます。

文法としては、

`キー名 : { (バリデーションの種類) : (バリデーションの値) }`

です。例えば　

` "name" : { "$type" : "string"} `

といった感じです。よく使うバリデーションの種類は以下でしょう。

|バリデーションの種類| 説明 |バリデーションの値|
|------------------|------|----------------|
|`$exists`  | キーが存在するか| `true`,`false`|
|`$type`  | 値の型が正しいか| "number","string" 等|
|`$in`    | 値が配列に含まれるか | 想定するキーの値を含む配列 |
|`$regex` | 値が正規表現とマッチするか | 正規表現 |

その他のバリデーションの種類については、find()などの条件指定方法と同じであるため、以下を参照してください。

https://docs.mongodb.org/manual/reference/operator/query/#query-selectors

ただし`$near`, `$nearSphere`, `$text`, `$where`は使えません。

また、配列かどうかをバリデーションしたい場合は

```
db.createCollection("user" , { validator : { "hoge" : {$type : "array" }}})
```

ではなく

```
db.createCollection("user" , { validator : { "hoge.0" : {$exists : true}}})
```

としないといけないため、注意が必要です。

## バリデーションのレベル(validationLevel)

以下の二つがあります。

* strict : 全ての挿入と更新が対象になる (デフォルト)
* moderate : 挿入と、既存の正しいドキュメントに対しての更新が対象になる。既存の正しくないドキュメントは対象にならない。
 


## 正しくないドキュメントを検出したときの動き(validationAction)

以下の二つがあります。

* error : ドキュメントの挿入・更新に失敗する  (デフォルト)
* warn : ドキュメントの挿入・更新は成功するが、ログに以下のような警告が出る

```
2016-04-26T00:58:01.200+0900 W STORAGE  [conn7] Document would fail validation collection: test.user doc: { _id: ObjectId('571e3e8904949114afa69d29'), name: 1.0, age: 1.0 }

```

## 参考

Validationについて書いた公式ドキュメントは情報不足なので、createCollectionのマニュアルを読むことをお勧めします。→　https://docs.mongodb.org/manual/reference/method/db.createCollection/

## 所感

省エネで作ったという感触を受けます。エラーメッセージは固定文言ですし、コマンドはほぼ生コマンド、チェックロジックも条件検索の使いまわしです（まあ、それで十分ですが）。