MongoDB 配列の更新

MongoDBBeginner
オンラインで実践に進む

はじめに

この実験 (Lab) では、MongoDB ドキュメント内の配列を操作する方法を学びます。MongoDB の強力な更新演算子を使用して、配列要素の追加、削除、更新を実践します。この実験では、MongoDB データベースでの配列管理を習得するための段階的な指示と実践的な例を提供します。

まず、$push 演算子を使用して配列に要素を追加します。次に、$pull および $pullAll 演算子を使用して要素を削除する方法を学びます。また、配列内の特定の要素を変更する方法や、$addToSet を使用して配列に一意の要素のみが含まれるようにする方法についても説明します。最後に、集計パイプラインを使用して既存の重複要素を配列から削除する方法を学びます。

$push を使用した配列への要素の追加

このステップでは、MongoDB ドキュメント内の配列に新しい要素を追加する方法を $push 演算子を使用して学習します。この演算子は、指定された値を配列の末尾に追加します。

まず、MongoDB シェルを開いてデータベースと対話します。この実験 (Lab) でのすべてのデータベース操作は、このシェル内で行われます。

mongosh

シェルに入ったら、arraylab データベースに切り替えます。このデータベースは、セットアッププロセス中に作成されました。

use arraylab

セットアップスクリプトは、1 つのドキュメントを持つ students コレクションも作成しました。このドキュメントを見つけて、現在の状態を確認しましょう。

db.students.findOne({ name: "Alice Johnson" })

以下のような出力が表示され、Alice が 2 つのコースに登録していることがわかります。

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [ 'Mathematics', 'Computer Science' ]
}

次に、$push 演算子を使用して、Alice の courses 配列に新しいコース「Data Structures」を追加しましょう。

db.students.updateOne(
    { name: "Alice Johnson" },
    { $push: { courses: "Data Structures" } }
)

updateOne メソッドは、フィルター { name: "Alice Johnson" } に一致するドキュメントを見つけ、更新 { $push: { courses: "Data Structures" } } を適用します。$push 演算子は、新しいコースを courses 配列の末尾に追加します。

$push$each 修飾子を組み合わせることで、一度に複数の要素を追加することもできます。「Physics」と「Chemistry」を配列に追加しましょう。

db.students.updateOne(
    { name: "Alice Johnson" },
    { $push: { courses: { $each: ["Physics", "Chemistry"] } } }
)

すべての新しいコースが追加されたことを確認するには、再度 findOne コマンドを実行します。

db.students.findOne({ name: "Alice Johnson" })

更新されたドキュメントには、5 つのコースすべてが含まれています。

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [
    'Mathematics',
    'Computer Science',
    'Data Structures',
    'Physics',
    'Chemistry'
  ]
}

配列からの要素の削除

このステップでは、$pull および $pullAll 演算子を使用して配列から要素を削除する方法を学習します。$pull は指定された値のすべてのインスタンスを削除し、$pullAll は複数の指定された値のすべてのインスタンスを削除します。

前のステップから引き続き mongosh シェルを使用しているはずです。まず、$pull 演算子を使用して Alice のリストから「Physics」コースを削除しましょう。

db.students.updateOne(
    { name: "Alice Johnson" },
    { $pull: { courses: "Physics" } }
)

このコマンドは、「Alice Johnson」のドキュメントを見つけ、彼女の courses 配列から文字列「Physics」を削除します。

次に、複数のコースを一度に削除しましょう。$pullAll 演算子がこれに最適です。「Mathematics」と「Chemistry」を削除します。

db.students.updateOne(
    { name: "Alice Johnson" },
    { $pullAll: { courses: ["Mathematics", "Chemistry"] } }
)

それでは、ドキュメントの最終状態を確認して、どのコースが残っているか見てみましょう。

db.students.findOne({ name: "Alice Johnson" })

出力は、「Physics」、「Mathematics」、「Chemistry」が削除され、2 つのコースのみが残っていることを示しています。

{
  _id: ObjectId('...'),
  name: 'Alice Johnson',
  courses: [ 'Computer Science', 'Data Structures' ]
}

配列内の特定の要素の更新

このステップでは、配列内の特定の要素を更新する方法を学習します。これは、配列にオブジェクトが含まれており、それらのオブジェクトのいずれかのフィールドを更新する必要がある場合に便利です。

まず、新しい学生ドキュメントを挿入しましょう。このドキュメントの courses 配列には、namegrade を持つオブジェクトが含まれます。

db.students.insertOne({
    name: "Bob Smith",
    courses: [
        { name: "Mathematics", grade: "B" },
        { name: "Computer Science", grade: "A" },
        { name: "Physics", grade: "C" }
    ]
})

Bob の「Computer Science」の成績を「A」から「A+」に変更したいとします。ここで位置指定子 $ を使用できます。この演算子は、クエリ条件に一致する最初の要素のプレースホルダーとして機能します。

db.students.updateOne(
    { name: "Bob Smith", "courses.name": "Computer Science" },
    { $set: { "courses.$.grade": "A+" } }
)

このコマンドでは、クエリ { "courses.name": "Computer Science" } が正しい配列要素を特定します。次に、更新 { $set: { "courses.$.grade": "A+" } }$ を使用してその要素を参照し、その grade フィールドを更新します。

変更を確認しましょう。

db.students.findOne({ name: "Bob Smith" })

出力には更新された成績が表示されます。

{
  _id: ObjectId('...'),
  name: 'Bob Smith',
  courses: [
    { name: 'Mathematics', grade: 'B' },
    { name: 'Computer Science', grade: 'A+' },
    { name: 'Physics', grade: 'C' }
  ]
}

すべて位置指定子演算子 $[ ] を使用して、配列内のすべての要素を一度に更新することもできます。Bob のすべてのコースに semester フィールドを追加しましょう。

db.students.updateOne(
    { name: "Bob Smith" },
    { $set: { "courses.$[].semester": "Fall 2023" } }
)

最終的なドキュメントを確認して、結果を見てみましょう。

db.students.findOne({ name: "Bob Smith" })

配列内のすべてのコースオブジェクトに semester フィールドが追加されました。

{
  _id: ObjectId('...'),
  name: 'Bob Smith',
  courses: [
    { name: 'Mathematics', grade: 'B', semester: 'Fall 2023' },
    { name: 'Computer Science', grade: 'A+', semester: 'Fall 2023' },
    { name: 'Physics', grade: 'C', semester: 'Fall 2023' }
  ]
}

$addToSet によるユニークな要素の保証

このステップでは、$addToSet 演算子の使用方法を学習します。この演算子は、配列に要素がまだ存在しない場合にのみ配列に要素を追加するため、重複エントリを防ぎます。

まず、スキル配列を持つ新しい学生を追加しましょう。

db.students.insertOne({
    name: "Emma Wilson",
    skills: ["Python", "JavaScript"]
})

次に、$addToSet を使用して再度「Python」を追加してみましょう。配列には既に「Python」が存在するため、この操作ではドキュメントは変更されません。

db.students.updateOne(
    { name: "Emma Wilson" },
    { $addToSet: { skills: "Python" } }
)

ドキュメントを確認して確認しましょう。

db.students.findOne({ name: "Emma Wilson" })

「Python」が既に存在していたため、skills 配列が変更されていないことがわかります。

{
  _id: ObjectId('...'),
  name: 'Emma Wilson',
  skills: [ 'Python', 'JavaScript' ]
}

$push と同様に、$addToSet$each 修飾子と組み合わせて複数の値を追加できます。配列にまだ存在しない値のみが追加されます。

db.students.updateOne(
    { name: "Emma Wilson" },
    { $addToSet: {
        skills: {
            $each: ["React", "Node.js", "Python", "TypeScript"]
        }
    } }
)

最終的なドキュメントを確認しましょう。

db.students.findOne({ name: "Emma Wilson" })

新しくユニークなスキルが追加され、重複していた「Python」は無視されました。

{
  _id: ObjectId('...'),
  name: 'Emma Wilson',
  skills: [ 'Python', 'JavaScript', 'React', 'Node.js', 'TypeScript' ]
}

配列から既存の重複を削除する

$addToSet は新しい重複の追加を防ぎますが、配列に既に重複する値が含まれているドキュメントがある場合があります。このステップでは、集計パイプラインを使用して既存の重複を削除する方法を学びます。

まず、重複を含む skills 配列を持つドキュメントを挿入しましょう。

db.students.insertOne({
    name: "Michael Chen",
    skills: ["Python", "JavaScript", "Python", "React", "JavaScript", "Node.js"]
})

これらの重複を削除するために、$merge ステージを持つ集計パイプラインを使用できます。このパイプラインはドキュメントを読み込み、一意の要素を持つ新しい配列を作成し、元のドキュメントを更新します。

まず、$merge 操作が正しく機能するように name フィールドにインデックスを作成する必要があります。

db.students.createIndex({ name: 1 }, { unique: true })

次に、次の集計コマンドを実行します。

db.students.aggregate([
    { $match: { name: "Michael Chen" } },
    { $project: {
        name: 1,
        skills: { $setUnion: "$skills" }
    } },
    { $merge: { into: "students", on: "name", whenMatched: "replace" } }
])

このパイプラインを分解してみましょう。

  1. $match: このステージは、処理するドキュメントを "Michael Chen" のものだけに絞り込みます。
  2. $project: このステージはドキュメントの形状を変更します。name フィールドを保持し、skills 配列を $setUnion: "$skills" の出力で置き換えます。$setUnion 演算子は配列を受け取り、一意の要素のみを含む新しい配列を返します。
  3. $merge: このステージは、パイプラインの結果を students コレクションに書き戻します。name フィールド (on: "name") に基づいて更新するドキュメントを見つけ、パイプラインからの新しいドキュメントでドキュメント全体を置き換えます (whenMatched: "replace")。作成したインデックスは、効率的なマッチングと更新を保証します。

次に、重複が削除されたことを確認しましょう。

db.students.findOne({ name: "Michael Chen" })

出力には、一意の要素のみを含む skills 配列が表示されます。要素の順序は異なる場合があります。

{
  _id: ObjectId('...'),
  name: 'Michael Chen',
  skills: [ 'JavaScript', 'Node.js', 'Python', 'React' ]
}

まとめ

この実験では、MongoDB で配列を管理するためのいくつかの重要なテクニックを学びました。$push で要素を追加し、$pull および $pullAll で削除し、位置指定演算子 $ を使用して特定の要素を更新する練習をしました。また、$addToSet を使用して配列内のユニークな要素を維持する方法や、$setUnion および $merge を使用した集計パイプラインで既存の重複をクリーンアップする方法についても学習しました。これらのスキルは、MongoDB を使用して動的で堅牢なアプリケーションを構築するための基本となります。