[Node.js] MongoDB のドキュメントの特定のプロパティを更新する方法

[Node.js] MongoDB のドキュメントの特定のプロパティを更新する方法

こんにちは。最近、友人と博多に旅行してきた k-so16 です。学問の神様にお参りに行ったり、美味しい博多の料理を食べたりと、博多を満喫してきました(笑)

サービスの試作で、データベースに MongoDB を使用しています。 Node.js から MongoDB のデータを更新する際に、ドキュメント全体ではなく、 特定のプロパティを更新 したいと思ったのですが、Node.js 用のドライバーのリファレンス にはドキュメント全体を更新する方法しか見当たりませんでした。

本記事では、 Node.js 経由でドキュメントの特定のプロパティのみを更新する方法について紹介します。

本記事で想定する読者層は以下の通りです。

  • ドキュメント志向データベースの基礎的な知識を有している
  • MongoDB を Node.js 経由でアクセスする方法を知っている

ドキュメントの特定のプロパティの更新方法

ドキュメントの特定のプロパティを更新する場合も、ドキュメント全体を更新する場合と同様に update()updateOne() などの Collection クラスのメソッドを利用します。

特定のプロパティの値を変更する 場合と 配列のプロパティにデータの追加や削除をする 場合で、第 2 引数に指定するオブジェクトのキーが異なります。また、 配列の特定の要素階層構造になっているプロパティの値 を指定する際に、更新対象を指定するキーの書き方が少々特殊になります。

本記事では、以下の構造のドキュメントについてデータの更新を行う場合を考えます。

本記事で更新するドキュメント
{
  "name": "博多旅行",
  "description": "2泊3日で博多を満喫する",
  "items": [
    {
      "date": "2020-02-22T10:00:00+0900",
      "name": "博多駅到着",
      "location": {
        "name": "JR博多駅",
        "address": "〒812-0012 福岡県福岡市博多区博多駅中央街1−1"
      },
      "description": "新大阪から博多まで新幹線で移動"
    }
  ]
}

なお、本記事ではオブジェクトを指定するために、ドキュメントごとに割り振られる オブジェクト ID を利用することとし、オブジェクト ID は 0123456789abcdef0123456789abcd とします。オブジェクト ID を指定するためには、 update() 系のメソッドの第 1 引数のオブジェクトのキーに _id を指定し、バリューに mongodb モジュールの ObjectID() メソッドにオブジェクト ID を指定します。

以降のプログラム例では、それぞれ mongorequire('mongodb') で取得したオブジェクト、 collectionmongo.MongoClient のオブジェクトとします。

ドキュメント内の配列に要素を追加・削除する方法

要素の追加

配列に要素を追加する場合は、更新対象のオブジェクトのキーに $push を指定します。要素は 配列の最後 に追加されます。

例として、 items の配列に要素を追加するコードを記述します。

items に要素を追加するコード例
await collection.updateOne({
  _id: mongo.ObjecID('0123456789abcdef0123456789abcd'),
}, {
  $push: {
    items: {
      date: "2020-02-22T13:00:00+0900",
      name: "太宰府天満宮参拝",
      location: {
        name: "太宰府天満宮",
        address: "〒818-0117 福岡県太宰府市宰府4丁目7−1"
      },
      description: "学問の神様にお参りしつつ梅ヶ枝餅をいただく"
    },
  },
});

要素の削除

配列から要素を削除する場合は、更新対象のオブジェクトのキーに $pull を指定します。削除対象の要素は条件を指定することで指定できます。

例として、 items に追加した要素を削除するコードを記述します。

items から要素を削除するコード例
await collection.updateOne({
  _id: mongo.ObjecID('0123456789abcdef0123456789abcd'),
}, {
  $pull: {
    items: { name: "太宰府天満宮参拝" },
  },
});

削除する要素が先頭または末尾の場合、 $pull の代わりに $pop を指定することも可能です。先頭を削除対象として指定する場合は条件に -1 を、末尾を指定する場合は 1 を指定します。

$push$pull などの 更新の指定子については、 Node.js のドライバーのドキュメントではなく、MongoDB の公式リファレンス に詳細が記述されていました。 せめてリンクだけでも貼っておいてくれれば探す手間もかなり省けたのですが… (^^;

Update Operators — MongoDB Manual

配列の要素や他階層のプロパティの更新

ドキュメント内の多階層にある特定のプロパティを更新する場合、 プロパティ名をドット (.) で連結した文字列 を更新対象のキーとして指定します。配列の特定の要素を指定する場合は、 要素の添字番号 を指定します。

例えば、items の先頭の要素の name プロパティを参照したい場合は、 items.0.name が更新対象のキーとなります。

ドキュメント内の配列の要素を更新する方法

配列の特定の要素を丸ごと更新する場合は、キーを 更新対象の配列.添字番号 と指定し、更新したいデータを update() などのメソッドの第 2 引数に指定します。指定の要素内に更新対象のプロパティが多い場合は、配列の要素全体を更新した方が単純でしょう。

以下のプログラムは、 items の先頭の要素を更新する例です。

items の先頭の要素を更新するコード例
await collection.updateOne({
  _id: mongo.ObjecID('0123456789abcdef0123456789abcd'),
}, {
  $set: {
    'items.0': {
      "date": "2020-02-22T11:30:00+0900",
      "name": "福岡空港到着",
      "location": {
        "name": "福岡空港",
        "address": "〒812-0003 福岡県福岡市博多区大字下臼井778−1"
      },
      "description": "新千歳空港から福岡空港まで飛行機で移動"
    },
  },
});

多階層のプロパティを変更する方法

ドキュメントの特定のプロパティのみを更新したい際に、多階層のプロパティを更新対象とする場合も同様にドットでプロパティ名を連結して更新対象の要素を指定します。

以下のプログラムは、 items の先頭要素の date プロパティを更新する例です。

items の先頭の要素の date プロパティを更新するコード例
await collection.updateOne({
  _id: mongo.ObjecID('0123456789abcdef0123456789abcd'),
}, {
  $set: {
    'items.0.date': '2020-02-21T22:30:00+0900',
  },
});

ドキュメントの多階層のプロパティや特定の配列の要素を指定する記法についても、 Dot Notation の項目が 公式ドキュメント に記載されていました。

Documents — MongoDB Manual

まとめ

本記事のまとめは以下の通りです。

  • 配列に追加や削除をする場合は $push$pull などの操作指定子を指定
  • 配列の特定の要素や多階層のプロパティを更新する場合は Dot Notation によって更新対象を指定

以上、 k-so16 でした。公式ドキュメントはしっかり読むようにしましょう(笑)

k-so16