[Mongoose] Error: Unable to invalidate a subdocument that has not been added to an array. の解決方法
Mongoose で Error: Unable to invalidate a subdocument that has not been added to an array. が発生したときの調査方法をご紹介します。
まず、結論から書いておくと type: ObjectId と定義している field に ObjectId 形式ではない不正な値を保存しようとしてエラーが発生していたようでした。
Mongoose エラーメッセージ
Error: Unable to invalidate a subdocument that has not been added to an array.
'use strict';
const { Schema } = require('mongoose');
const { ObjectId } = Schema;
const RegiTransaction = new Schema(
  {
    transactionHead: {
      type: Schema.Types.Mixed
    },
    details: [
      {
        transactionDetail: {
          type: Schema.Types.Mixed
        },
        sku: {
          type: ObjectId,
          ref: 'Sku'
        }
      }
    ]
  }
);
以下のような update クエリを実行すると Error: Unable to invalidate a subdocument that has not been added to an array. が発生しました。
cost data = {
  details: [
    {
      transactionDetail: {
        foo: 'bar'
      },
      sku: 'Invalid ObjectId'
    }
  ]
};
await RegiTransaction.update(
  {
    _id: targetId
  },
  {
    $set: data
  },
  {
    upsert: true
  }
);
対策案として update クエリを実行する前に、RegiTransaction.details.sku に保存される予定の値が ObjectId 形式であることを検証する validation 処理を追加することで Mongoose エラーを起こさずに未然にエラーハンドリングできます。
以上、Mongoose で Error: Unable to invalidate a subdocument that has not been added to an array. を調査・解決した、現場からお送りしました。