コンパイラかく語りき

import { Fun } from 'programming'

【Node.js】Mongoose の upsert で、 ドキュメント作成時のみ追加するフィールド

Mongoose の upsert 便利ですよね。正しくは、upsert: true オプションですね。ドキュメントが存在しなければ作成、存在すれば更新をしてくれます。

参考: How do I update/upsert a document in Mongoose? - stackoverflow.com

さてそんな upsert を行う時、作成時のみに何かしたいというケースがあります。例えば、 created_at のようなフィールドの作成でしょうか。一度作成されたら更新されたくない、といったフィールドです。

そんな時、 $setOnInsert が便利です。

以下、サンプルコードです。

import mongoose from '../libs/mongoose';

const { Schema } = mongoose;

// schema
const ThingSchema = new Schema({
  id: Number,
  name: String,
  created_at: Date,
  updated_at: Date,
});

const Thing = mongoose.model('Thing', ThingSchema);

Thing.upsertThing = (thingId, thingName) => Thing.findOneAndUpdate(
  // ドキュメント検索条件
  { id: thingId },

  // ドキュメントデータ
  {
    // 常に適用される
    $set: {
      id: thingId,
      name: thingName,
      updated_at: new Date(),
    },
    // 作成時にのみ適用される
    $setOnInsert: {
      created_at: new Date(),
    },
  },

  // オプション
  { new: true, upsert: true },
)

$setOnInsert - docs.mongodb.com

If an update operation with upsert: true results in an insert of a document, then $setOnInsert assigns the specified values to the fields in the document. If the update operation does not result in an insert, $setOnInsert does nothing.