次期バージョンMongoDB 4.2の新機能Wildcard Indexを試す

# 概要
MongoDBの次期バージョン4.2の新機能であるWildcard Indexを試してみる

# 環境
- Windows10
- MongoDB 4.2.0-RC5

# データの挿入

```javascript
for(var i = 0; i < 200000; i++) {
   db.col.insert({a:i, b:i+"bbbbbbbbbbbbbbbbbbb", c:i+"ccccccccccccccccccc"})
}
```

# Indexのサイズの比較

フィールドa,b,cそれぞれにIndexを作成します。

```javascript
db.col.createIndexes([{a:1},{b:1},{c:1}])
```
```json
{
        "createdCollectionAutomatically" : false,
        "numIndexesBefore" : 1,
        "numIndexesAfter" : 4,
        "ok" : 1
}
```

Indexのサイズを確認します

```javascript
db.col.stats()
```

出力は途中省略しています

```json
        "nindexes" : 4,
        "indexBuilds" : [ ],
        "totalIndexSize" : 16498688,
        "indexSizes" : {
                "_id_" : 1523712,
                "a_1" : 2433024,
                "b_1" : 6270976,
                "c_1" : 6270976
        },
```

今作成したIndexをすべて削除します

```javascript
db.col.dropIndexes()
```

フィールドa,b,cの代わりにコレクション全体にIndexを作るWildcard Indexを作成します

```javascript
db.col.createIndex({"$**":1})
```

Indexのサイズを確認します


```javascript
db.col.stats()
```

出力は途中省略しています

```json
        "nindexes" : 2,
        "indexBuilds" : [ ],
        "totalIndexSize" : 16388096,
        "indexSizes" : {
                "_id_" : 1847296,
                "$**_1" : 14540800
        },
```

合計サイズはWildcard Indexのが若干小さいですが、ほぼ同じです。
クエリで実際にIndexが使われるかはexpalin()で確認してください。結果は省略します。

```javascript
db.col.find({a:100}).explain("executionStats")
```

当然Wildcard Indexは後で追加された項目にもIndexが作成されます。
例）

```javascript
db.col.insert({d:"ddddd"})
```

次のクエリにもIndexが使われますのでexplain()で確認してください。

```javascript
db.col.find({d:"ddddd"})
```

# 実際的なWildcard Indexの使い方

上記ではドキュメントのトップレベルにWildcard Indexを作成しまたが、Indexが不必要はフィールドにもIndexが作られてしまいます。そこで実際的にはIndexが必要なフィールドだけ集めてサブドキュメントとすることが考えられます。
テスト用のドキュメント(col2)を作ります。

```javascript
db.col2.insert({a:1, sub:{x:1, y:2}})
db.col2.insert({a:2, sub:1})
db.col2.insert({a:3, sub:[1,2,3]})
db.col2.insert({a:4, sub:{x:[1,2,3], y:3}})
```

`sub`にWildcard Indexを作成します。

```javascript
db.col2.createIndex({"sub.$**":1})
```

次のクエリはIndexが使われますので、explain()で確認してください。

```javascript
db.col2.find({"sub":1})
```
```
{ "_id" : ObjectId("5d43b0618d76ec6d008af83a"), "a" : 2, "sub" : 1 }
{ "_id" : ObjectId("5d43b0618d76ec6d008af83b"), "a" : 3, "sub" : [ 1, 2, 3 ] }
```
```javascript
db.col2.find({"sub.x":1})
```
```
{ "_id" : ObjectId("5d43b0618d76ec6d008af839"), "a" : 1, "sub" : { "x" : 1, "y" : 2 } }
{ "_id" : ObjectId("5d43b0628d76ec6d008af83c"), "a" : 4, "sub" : { "x" : [ 1, 2, 3 ], "y" : 3 } }
```

しかし、次のクエリはIndexは使われません

```javascript
db.col2.find({sub:{x:1, y:2}})
db.col2.find({sub:[ 1, 2, 3 ]})
```

複雑な`sub`を追加

```javascript
db.col2.insert({a:5,sub:{a:[{x:1,y:2},{x:[2,3], y:2}]}})
```

次のクエリもIndexが使われます

```javascript
db.col2.find({"sub.a.x":2})
```
```
{ "_id" : ObjectId("5d43bdf22288321167e05b9f"), "a" : 5, "sub" : { "a" : [ { "x" : 1, "y" : 2 }, { "x" : [ 2, 3 ], "y" : 2 } ] } }
```

# Wildcard Index一部指定

```javascript
db.col.createIndex(
  { "$**" : 1 },
  { "wildcardProjection" :
    { "a" : 1, "b.c" : 1 }
  }
)
```

これは次の指定と似ています

```javascript
db.col.createIndex({"a.$**":1})
db.col.createIndex({"b.c.$**":1})
```

`wildcardProjection`との違いはIndexの物理ファイルが2個になることです。

# Wildcard Indexの一部除外

```javascript
db.col.createIndex(
  { "$**" : 1 },
  { "wildcardProjection" :
    { "a" : 0, "b.c" : 0 }
  }
)
```
一部排除は`1`ではなく`0`を設定します。
フィールド名が`x`,`y`など`wildcardProjection`で設定されていないフィールドはIndexが作成されます。

# 制限事項

### サポートされていないIndex

- Compound
- TTL
- Text
- 2d (Geospatial)
- 2dsphere (Geospatial)
- Hashed
- Unique

### サポートされていないクエリ

- `{$exists: false}`
- クエリの値としての配列やドキュメント
    - `find({a:[1,2,3])`  //配列
    - `find({a:{x:1}})`   //ドキュメント
- `$ne`を使って`null`以外の検索
    - `find({$ne:["a.b", null]})
- aggregationで`$max`,`$min`を使った値の取り出し
- Sharding


# まとめ

- 複数のIndexを一つの設定で作られる
- 将来増える未定の項目についてもIndex設定がされている
- Wildcard Indexが設定されたフィールド配下にネストされたドキュメントのフィールドにもIndexが作られます
- 以上のように少ない設定で効率的にIndexが設定されるのですごく便利になると思います。ただし、Wildcard Indexの物理ファイルが巨大化しそうです。

# 参照

- https://docs.mongodb.com/master/core/index-wildcard/
- https://docs.mongodb.com/master/reference/index-wildcard-restrictions/