MongoDBエラーの解決方法:$unwind: value at end of field path was not an array

中級🍃 MongoDB2026-06-12| MongoDB 3.2以降, MongoDB Atlas, Node.js/Python/Go ドライバ, すべてのOS (Linux, Windows, macOS)

Error Message

PlanExecutor error during aggregation :: caused by :: $unwind: value at end of field path ... was not an array
#mongodb#aggregation#unwind#database-errors#nosql

問題の概要MongoDBの集計(aggregation)パイプラインを構築している際、すべて順調に見えていたのに突然クラッシュすることがあります。配列を個別のドキュメントに展開するはずの $unwind ステージで問題が発生したのです。期待していたクリーンなデータの代わりに、次のような苛立たしいエラーが表示されます。

PlanExecutor error during aggregation :: caused by :: $unwind: value at end of field path 'yourFieldName' was not an array

これが起こる理由は、$unwind の制約によるものです。このステージは厳密に配列を分解するために設計されています。パイプラインが処理するドキュメントの中に、対象のフィールドが文字列、整数、または真偽値であるものが1つでも含まれていると、操作全体が停止してしまいます。

根本原因原因のほとんどは、データの不整合です。MongoDBのスキーマレスな性質は柔軟性において優れていますが、アプリケーションのロジックが厳密でない場合、「汚れた」データが混入する可能性があります。例えば、以下のようなケースでこの問題が発生します。

  • レガシースクリプトが、単一のタグを配列(["marketing"])ではなく文字列("marketing")として保存していた。- フロントエンドのバグにより、ユーザーがIDのリストではなく単一の数値IDを送信できてしまった。- CSVや外部APIからデータをインポートした際、単一の項目に対して配列型が厳密に強制されていなかった。## エラーの修正方法### 方法1:クイックフィルター有効な配列を含むドキュメントのみを処理すればよい場合は、$unwind の直前に $match ステージを追加するのが最も簡単な解決策です。これがセーフティゲートとして機能し、互換性のあるデータのみが後続の処理に渡されるようになります。
db.collection.aggregate([
  {
    $match: {
      "yourFieldName": { $type: "array" }
    }
  },
  {
    $unwind: "$yourFieldName"
  }
])

$type: "array" を使用することで、フィールドが文字列、数値、または null であるドキュメントを実質的に無視できます。これにより、予期しない型でクラッシュすることなく、パイプラインをスムーズに実行し続けることができます。

方法2:実行時に変換するデータの形式が正しくないからといって、無視できない場合もあります。フィールドが単一の値か配列かに関わらず、すべてのドキュメントを処理する必要がある場合は、$unwind ステージの前に $addFields を使用して、単一の値を配列でラップします。

db.collection.aggregate([
  {
    $addFields: {
      "yourFieldName": {
        $cond: {
          if: { $isArray: "$yourFieldName" },
          then: "$yourFieldName",
          else: { 
            $ifNull: [ ["$yourFieldName"], [] ] 
          }
        }
      }
    }
  },
  {
    $unwind: "$yourFieldName"
  }
])

このロジックはフィールドの型をチェックします。すでに配列であればそのまま維持し、単一の値(例えば文字列の "urgent")であれば、ブラケットで囲んで ["urgent"] に変換します。これにより、問題なく展開(unwind)できるようになります。

方法3:恒久的な修正(データのクリーンアップ)クエリでのその場しのぎの対応も役立ちますが、データベースをクリーンアップすることが最も信頼できる長期的な解決策です。1回限りのマイグレーションスクリプトを実行して、コレクション内の配列でない値をすべて見つけて変換します。

// フィールドが存在するが配列ではないすべてのドキュメントを更新する
db.collection.find({
  "yourFieldName": { $exists: true, $not: { $type: "array" } }
}).forEach(function(doc) {
  db.collection.updateOne(
    { _id: doc._id },
    { $set: { "yourFieldName": [doc.yourFieldName] } }
  );
});

検証手順修正がうまくいったと思い込まないようにしましょう。変更を適用した後、簡単な診断チェックを行ってデータがクリーンであることを確認します。countDocuments を使用して、対象外のデータを探します。

db.collection.countDocuments({ 
  "yourFieldName": { $exists: true, $not: { $type: "array" } } 
})

結果が 0 であれば、$unwind ステージは安全です。もし数百や数千といった数値が表示される場合は、まだ対処が必要な不整合なデータが残っています。

予防のためのヒント- スキーマバリデーション: MongoDBのJSON Schemaバリデーションを使用して、フィールドが配列であることを強制します。これにより、不正なデータがコレクションに混入するのを防ぎます。- Mongooseスキーマ: Node.jsを使用している場合は、フィールドを tags: [String] のように定義します。Mongooseは値を自動的に配列にキャストしようと試みます。- 防御的な集計: データは常に「汚れている」可能性があるものとして扱いましょう。パイプライン内で $isArray チェックを使用することで、予期しないデータ状態に対するアプリケーションの耐性が大幅に向上します。

Related Error Notes