序章
ドキュメントに値がない場合、DB はその値を と見なしますnull
。次のドキュメントを含むデータベースがあるとします。
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
フィールドdescがnullとは異なるドキュメントを検索するクエリを作成すると、ドキュメントが1 つだけ取得されます。
db.test.find({desc: {$ne: null}})
// Output:
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
データベースは、 descフィールドのないドキュメントと、descフィールドの値がnullのドキュメントを区別しません。もう 1 つのテスト:
db.test.find({desc: null})
// Output:
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
ただし、上記の最後の例に示すように、フィールドは引き続きディスクに保存され、MongoDB に送信されたドキュメントと同じ構造のドキュメントを受け取るため、違いはクエリでのみ無視されます。
質問
たとえば、空の文字列を挿入する場合など、「空の」データを処理する場合、デフォルトで null にするか、「」にするか、まったく挿入しないでください。
ほとんどの演算子は同じ結果になるため、 {desc: null}
toとの違いはほとんどありません。次の 2 つの演算子だけに特に注意を払う必要があります。{}
演算子は引き続き期待どおりに動作し、スペースを節約できるため、 descフィールドなしでドキュメントを保存します。
パディング係数
データベース内のドキュメントが頻繁に大きくなることがわかっている場合、以前のドキュメントの場所に十分なスペースがないため、MongoDB は更新中にドキュメントを移動する必要がある場合があります。ドキュメントの移動を防ぐために、MongoDB は各ドキュメントに余分なスペースを割り当てます。
ドキュメントごとに MongoDB によって割り当てられる余分なスペースの量は、パディング ファクターによって制御されます。MongoDB は適応的にパディング係数を学習するため、パディング係数を選択することはできません (選択する必要はありません) が、可能性のある将来のフィールドにnull値を入力することで、MongoDB が各ドキュメントの内部スペースを事前に割り当てるのを助けることができます。その差は非常に小さく (アプリケーションによって異なります)、MongoDB が最適なパディング ファクターを学習した後はさらに小さくなる可能性があります。
疎索引
このセクションは、現在の特定の問題にとってそれほど重要ではありませんが、同様の問題に直面したときに役立つ可能性があります。
フィールドdescに一意のインデックスを作成すると、同じ値を持つ複数のドキュメントを保存できなくなります。以前のデータベースでは、フィールドdescに同じ値を持つ複数のドキュメントがありました。前に提示されたデータベースに一意のインデックスを作成して、どのようなエラーが発生するかを見てみましょう。
db.test.ensureIndex({desc: 1}, {unique: true})
// Output:
{
"err" : "E11000 duplicate key error index: test.test.$desc_1 dup key: { : null }",
"code" : 11000,
"n" : 0,
"connectionId" : 3,
"ok" : 1
}
一部のフィールドに一意のインデックスを作成し、一部のドキュメントでこのフィールドを空にできるようにしたい場合は、疎インデックスを作成する必要があります。一意のインデックスをもう一度作成してみましょう。
// No errors this time:
db.test.ensureIndex({desc: 1}, {unique: true, sparse: true})
ここまでは順調ですが、なぜこれをすべて説明する必要があるのでしょうか。スパース インデックスにはあいまいな動作があるためです。次のクエリでは、すべてのドキュメントがdescでソートされていると想定しています。
db.test.find().sort({desc: 1})
// Output:
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
結果は奇妙に思えます。紛失した書類はどうなりましたか。ソートせずにクエリを試してみましょう。
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
今回はすべての書類が返却されました。何が起こっていますか?シンプルですが、それほど明白ではありません。結果をdescでソートすると、以前に作成したスパース インデックスが使用され、 descフィールドを持たないドキュメントのエントリはありません。次のクエリは、インデックスを使用して結果を並べ替える方法を示しています。
db.test.find().sort({desc: 1}).explain().cursor
// Output:
"BtreeCursor desc_1"
ヒントを使用してインデックスをスキップできます。
db.test.find().sort({desc: 1}).hint({$natural: 1})
// Output:
{ "_id" : ObjectId("5192d23f1698aa96f0690d97"), "a" : 1, "desc" : null }
{ "_id" : ObjectId("5192d2441698aa96f0690d98"), "a" : 1 }
{ "_id" : ObjectId("5192d23b1698aa96f0690d96"), "a" : 1, "desc" : "" }
概要
- 含めた場合、疎な一意のインデックスは機能しません
{desc: null}
- 含めた場合、疎な一意のインデックスは機能しません
{desc: ""}
- スパース インデックスは、クエリの結果を変更する可能性があります