サイトアイコン IT NEWS

LambdaのNode.jsからMongoDBのデータが更新されない理由とその対策

Webアプリケーションやシステム開発でよく使われるNode.jsMongoDBの組み合わせ。
最近では、サーバーの構築をせずに使えるLambda関数(クラウド上の小さな処理単位)からMongoDBを更新したいという要望も増えてきました。

しかし実際に使ってみると、エラーが出ていないのにデータが更新されないという不可解な現象に遭遇することがあります。
今回は、このよくある問題の原因と、その対処法を丁寧に解説します。

問題の概要

例えば以下のように、MongoDBのドキュメント(データの1件)を更新する処理を書いたとします。

const { MongoClient, ObjectId } = require('mongodb');
const client = await MongoClient.connect("接続先の文字列", { useNewUrlParser: true, useUnifiedTopology: true });
const db = client.db("データベース名");

await db.collection("コレクション名").updateOne(
  { _id: ObjectId("対象のID") },
  { $set: { user_name: "テスト", update_dt: "1693795774031" } }
);

このコードは、あるデータのuser_nameupdate_dtを変更しようとしています。
実際にコマンドをターミナルやMongoDBの操作ツールで実行すると正しく動作します。

ところが、これをAWS Lambdaで実行した場合、「成功しました」という結果(例えばHTTPで200番の返答)が返るにもかかわらず、データがまったく変更されていないという現象が起こることがあります。

よくある原因とその確認ポイント

この問題の原因はいくつかあります。
見落としやすいところを中心に、確認すべきポイントを順番に紹介します。

対象のデータが存在しない

最もありがちなミスは、対象のIDに対応するデータが存在していないケースです。
MongoDBでは、条件に合うデータがない場合でもエラーにはなりません。modifiedCountが0であっても、処理としては「成功」と見なされます。

対策としては、以下のように条件に合う件数をチェックします。

if (result.modifiedCount === 0) {
  console.log("更新対象のデータが存在しない可能性があります。");
}

ObjectIdが手動で入力されている場合、誤字や桁数ミスも疑いましょう。

フィールドの型が一致していない

update_dtのように数値のような文字列を渡していると、データベース内の型と合わず更新されないことがあります。
MongoDBは型に敏感なため、例えば既に数値として保存されている場合に文字列で更新しようとするとスルーされることがあります。

$set: { update_dt: Number("1693795774031") } // 数値型で統一

権限が足りない

接続するMongoDBのユーザーに、書き込み権限がないとデータは変更できません。
これは、管理画面や設定ファイルで確認できます。
接続できる=書き込める、とは限らないので注意しましょう。

非同期処理を正しく待っていない

非同期処理の扱いもよくある落とし穴です。
Lambda関数は短時間で終了してしまうため、処理が完了する前に接続が閉じられていることがあります。

const result = await db.collection("コレクション名").updateOne(...);
console.log(result);

awaitを忘れずに使うことで、処理が完了するのを待つようにしましょう。

コレクション名やデータベース名の打ち間違い

些細なミスですが、コレクション名データベース名が正しくないと、意図しない別の場所で処理が行われていたり、処理自体が何もされていなかったりします。

一度、console.log(db.collection("コレクション名").find())などで確認しておきましょう。

正しい実装の例

以下は、上記のポイントをすべて押さえたLambda用のサンプルです。

const { MongoClient, ObjectId } = require('mongodb');

exports.handler = async (event) => {
  const client = await MongoClient.connect("接続先の文字列", { useNewUrlParser: true, useUnifiedTopology: true });
  const db = client.db("データベース名");

  try {
    const result = await db.collection("コレクション名").updateOne(
      { _id: ObjectId("対象のID") },
      { $set: { user_name: "テスト", update_dt: Date.now() } }
    );

    if (result.modifiedCount === 0) {
      console.log("データが見つからなかったか、すでに同じ内容です。");
    } else {
      console.log("データの更新に成功しました。");
    }

    return { statusCode: 200, body: "更新処理を完了しました" };
  } catch (err) {
    console.error("更新処理中にエラーが発生しました", err);
    return { statusCode: 500, body: "更新失敗" };
  } finally {
    client.close();
  }
};

まとめ

Node.jsからMongoDBを扱う際、単純な更新処理であっても意外と多くの注意点があります。
特に、AWS Lambdaのように一時的な処理環境では、非同期の待機漏れや型の違いなどが原因で、データが更新されないことがあります。

大事なのは、「エラーが出ない=成功」ではないということ。
必ず更新件数や条件に合致したかどうかを確認するようにしましょう。

モバイルバージョンを終了