未定義のデータとクエリの移行
項目一覧
MongoDB 8.0以降、等価一致式で null
と比較しても、 undefined
値と一致しません。
たとえば、これらのドキュメントとクエリについて考えてみます。
// people collection [ { _id: 1, name: null }, { _id: 2, name: undefined }, { _id: 3, name: [ "Gabriel", undefined ], { _id: 4, names: [ "Alice", "Charu" ] } ]
db.people.find( { name: null } )
MongoDB 8.0より前では、上記のクエリは次のドキュメントと一致します。
name
フィールドはnull
(_id: 1
)name
フィールドはundefined
またはundefined
配列要素を含みています(_id: 2
と_id: 3
)name
フィールドは存在しません(_id: 4
)
MongoDB 8.0 以降では、上記のクエリでは、name
フィールドが undefined
であるか、 または undefined
配列要素が含まれているドキュメントは一致しません。クエリは、次の条件を満たすドキュメントのみに一致します。
name
フィールドはnull
またはnull
配列要素を含みています(_id: 1
)name
フィールドは存在しません(_id: 4
)
このクエリ動作の変更は、次の操作にも影響します。
この動作の変更を考慮するには、次のことを実行します。
注意
undefined
は、非推奨のBSON type です。 MongoDB Shell とドライバーの最近のバージョンでは、挿入とアップデートを実行するときに、undefined
値を null
に自動的に変換します。このページのガイダンスは、古いドライバー バージョンまたはレガシーのmongo
シェルからの undefined
値を持つ配置に適用されます。
未定義フィールドの排除
ドキュメント内に undefined
値を持つフィールドを保持する必要がない場合は、それらのフィールドを削除できます。 MongoDB の柔軟なデータモデル、コレクションのドキュメントフィールドは一貫している必要はなく、ドキュメントのサブセットから特定のフィールドを削除できます。
ドキュメントから未定義のフィールドをどのように削除するかは、削除するフィールド名を知っているかどうかによって異なります。フィールド名がわかっている場合は、インデックスを使用できるため、操作のパフォーマンスが向上します。
次のいずれかを参照してください。
既知の名前のフィールドを削除
削除対象の undefined
値を含むフィールドの名前がわかっている場合は、次の例を使用します。この例では、people
コレクションを更新して次の要素を削除します。
値がスカラー値
undefined
である場合のname
フィールド。undefined
name
フィールドの配列要素。
db.people.updateMany( { name: { $type: "undefined" } }, [ { $set: { "name": { $cond: { // When "name" is an array, convert { name: [ "Alice", undefined ] } // to { name: [ "Alice" ] } if: { $eq: [ { $type: "$name" }, "array" ] }, then: { $filter: { input: "$name", cond: { $not: { $eq: [ { $type: "$$this" }, "undefined" ] } } }, }, // When "name" is scalar undefined, remove it else: "$$REMOVE" } } } } ] )
操作の実行後、people
コレクションには次のドキュメントが含まれます。
[ { _id: 1, name: null }, { _id: 2 }, { _id: 3, name: [ "Gabriel" ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
不明な名前のフィールドの排除
undefined
値が含まれるフィールドがわからない場合は、次の例を使用して、undefined
の最上位フィールドをすべて削除します。
注意
アップデートのフィールド名を指定しない場合、クエリはインデックスを使用できないため、操作はパフォーマンスが良くありません。大規模なコレクションで次の例を実行すると、クエリは遅くなり、リソースを消費する可能性があります。
次の例では、値が undefined
である people
コレクションから最上位のドキュメントフィールドを排除しています。
db.people.updateMany( { }, [ { $replaceWith: { // Detect undefined top-level fields under the root and remove them $arrayToObject: { $filter: { input: { $objectToArray: "$$ROOT" }, cond: { $not: { $eq: [ { $type: "$$this.v" }, "undefined" ] } } } } } } ] )
操作の実行後、people
コレクションには次のドキュメントが含まれます。
[ { _id: 1, name: null }, { _id: 2 }, { _id: 3, name: [ "Gabriel", undefined ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
注意
上記のアプローチでは、最上位のフィールドのみが変更されます。 _id: 3
を含むドキュメントには引き続き undefined
値が含まれます。これは、値が配列に表示されるためです。
未定義の値を null に更新
undefined
データ値を null
データ型に更新できます。このアプローチを使用して、ドキュメントフィールドを保持しながら、非推奨の undefined
データ型からデータを移行します。
未定義のフィールドをどのように更新するかは、更新対象のフィールド名がわかっているかどうかによって異なります。フィールド名がわかっている場合は、インデックスを使用できるため、操作のパフォーマンスが向上します。
次のいずれかを参照してください。
既知の名前でフィールドを更新
null
に設定したい undefined
値を含むフィールドの名前がわかっている場合は、次の例を使用します。この例では、people
コレクションを更新して、次の値を null
に設定します。
値がスカラー値
undefined
である場合のname
フィールド。undefined
name
フィールドに表示される配列要素。
db.people.updateMany( { name: { $type: "undefined" } }, [ { $set: { "name": { $cond: { // When "name" is an array, convert { name: [ "Alice", undefined ] } // to { name: [ "Alice", null ] } if: { $eq: [ { $type: "$name" }, "array" ] }, then: { $map: { input: "$name", in: { $cond: { if: { $eq: [ { $type: "$$this" }, "undefined" ] }, then: null, else: "$$this" } } }, }, // When "name" is the scalar undefined, convert to null else: null } } } } ] )
操作の実行後、people
コレクションには次のドキュメントが含まれます。
[ { _id: 1, name: null }, { _id: 2, name: null }, { _id: 3, name: [ "Gabriel", null ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
不明な名前を持つフィールドの更新
undefined
値が含まれるフィールドがわからない場合は、次の例を使用して、すべての undefined
の最上位フィールドを null
に設定します。
注意
アップデートのフィールド名を指定しない場合、クエリはインデックスを使用できないため、操作はパフォーマンスが良くありません。大規模なコレクションで次の例を実行すると、クエリは遅くなり、リソースを消費する可能性があります。
次の例では、people
コレクションを更新して、undefined
の最上位ドキュメントフィールドを null
に設定します。
db.people.updateMany( { }, [ { $replaceWith: { // Detect undefined top-level fields under the root and replace them with null $arrayToObject: { $map: { input: { $objectToArray: "$$ROOT" }, in: { $cond: { if: { $eq: [ { $type: "$$this.v" }, "undefined" ] }, then: { k: "$$this.k", v: null }, else: "$$this" } } } } } } ] )
操作の実行後、people
コレクションには次のドキュメントが含まれます。
[ { _id: 1, name: null }, { _id: 2, name: null }, { _id: 3, name: [ "Gabriel", undefined ] } { _id: 4, names: [ "Alice", "Charu" ] } ]
注意
上記のアプローチでは、最上位のフィールドのみが変更されます。 _id: 3
を含むドキュメントには引き続き undefined
値が含まれます。これは、値が配列に表示されるためです。
未定義の値に一致するようにクエリを更新する
データ型を null
から undefined
に移行できない場合は、未定義の値と一致するようにクエリを書き換えることができます。このアプローチを使用しても、データには非推奨の undefined
BSON型が引き続き含まれます。
null
のクエリが未定義の値と一致するようにするには、undefined
型に明示的に一致するクエリ述語を追加します。例、次のクエリは、name
が undefined
、 null
、または欠落しているドキュメントに一致します。
db.people.find( { $or: [ { name: null }, { name: { $type: "undefined" } } ] } )
このクエリでは、 people
コレクション内のすべてのドキュメントが返されます。
[ { _id: 1, name: null }, { _id: 2, name: undefined }, { _id: 3, name: [ "Gabriel", undefined ], { _id: 4, names: [ "Alice", "Charu" ] } ]