Mongooseスキーマにcreated_atおよびupdated_atフィールドを追加


166

new MyModel()が呼び出されるたびにそれらを渡す必要なしに、created_atおよびupdated_atフィールドをマングーススキーマに追加する方法はありますか?

created_atフィールドは日付であり、ドキュメントが作成されたときにのみ追加されます。ドキュメントでsave()が呼び出されるたびに、updated_atフィールドは新しい日付で更新されます。

私は自分のスキーマでこれを試しましたが、わざわざ追加しない限り、フィールドは表示されません。

var ItemSchema = new Schema({
    name    : { type: String, required: true, trim: true }
  , created_at    : { type: Date, required: true, default: Date.now }
});

私はあなたがしたことを正確に行い、それはうまくいきました。Mongoose 4.8.4の使用。新しいものかもしれませんか?
martinedwards、

1
これはかなり前のことです。
2018年

ええ、上記が機能することは注目に値するものだと思いました。
martinedwards

回答:


132

Mongoose 4.0以降、スキーマにタイムスタンプオプションを設定して、Mongooseで処理できるようになりました。

var thingSchema = new Schema({..}, { timestamps: true });

次のように、使用するフィールドの名前を変更できます。

var thingSchema = new Schema({..}, { timestamps: { createdAt: 'created_at' } });

http://mongoosejs.com/docs/guide.html#timestamps


2
これは、Mongoose 4.0の最良のオプションであることに同意しました。
Tadd Giles

258

更新:(5年後)

注:カッパアーキテクチャイベントソーシング+ CQRS)を使用する場合は、日付を更新する必要はありません。データは不変の追加専用のイベントログであるため、イベントの作成日のみが必要です。以下で説明するLambdaアーキテクチャに似ています。次に、アプリケーションの状態は、イベントログ(派生データ)の予測です。既存のエンティティに関する後続のイベントを受け取った場合は、そのイベントの作成日をエンティティの更新日として使用します。これは、miceroserviceシステムで一般的に使用されている(そして一般的に誤解されている)プラクティスです。

更新:(4年後)

フィールドObjectIdとして使用する場合_id(これは通常のケースです)、必要なことは次のとおりです。

let document = {
  updatedAt: new Date(),
}

作成したタイムスタンプを_idフィールドから取得する方法については、以下の元の回答を確認してください。外部システムのIDを使用する必要がある場合は、Roman Rhrn Nesterovの回答を確認してください。

更新:(2.5年後)

mongooseバージョン> = 4.0で#timestampsオプションを使用できるようになりました

let ItemSchema = new Schema({
  name: { type: String, required: true, trim: true }
},
{
  timestamps: true
});

セットタイムスタンプ、マングース割り当てた場合createdAtupdatedAtスキーマにフィールド、割り当てられたタイプがありますDate

タイムスタンプファイルの名前を指定することもできます。

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

注:重要なデータを含む大きなアプリケーションで作業している場合は、ドキュメントの更新を再検討する必要があります。不変の追加専用データ(ラムダアーキテクチャ)を使用することをお勧めします。これは、挿入のみを許可することを意味します。更新と削除は許可されるべきではありません!レコードを「削除」したい場合は、いくつかのtimestamp/ version ファイルを付けてドキュメントの新しいバージョンを簡単に挿入し、deletedフィールドをに設定できますtrue。同様に、ドキュメントを更新したい場合は、適切なフィールドを更新し、残りのフィールドをコピーして新しいドキュメントを作成します。次に、このドキュメントをクエリするために、最新のタイムスタンプまたは最新バージョンのドキュメントを取得します。 「削除」されません(deleted フィールドは未定義またはfalse`)です。

データの不変性により、データを確実にデバッグできます。すべてのドキュメントの履歴を追跡できます。何か問題が発生した場合は、ドキュメントの以前のバージョンにロールバックすることもできます。あなたがそのようなアーキテクチャで行くObjectId.getTimestamp()なら、あなたが必要とするすべてであり、それはマングースに依存していません。


元の回答:

IDフィールドとしてObjectIdを使用している場合、フィールドは必要ありませんcreated_at。ObjectIdにはと呼ばれるメソッドがありgetTimestamp()ます。

ObjectId( "507c7f79bcf86cd7994f6c0e")。getTimestamp()

これにより、次の出力が返されます。

ISODate( "2012-10-15T21:26:17Z")

詳細情報はこちらMongo ObjectIDから作成日を抽出する方法

フィールドを追加updated_atするには、これを使用する必要があります。

var ArticleSchema = new Schema({
  updated_at: { type: Date }
  // rest of the fields go here
});

ArticleSchema.pre('save', function(next) {
  this.updated_at = Date.now();
  next();
});

3
Mongoose / node.jsでそれをどのように行いますか?
Zebra Propulsion Lab

6
それは、使用されるソリューションではなくても、非常に興味深いことです。
2014

しかし、作成日をビューに渡したい場合は、これに特別な変数を設定するか、IDを渡す必要がありますか?

3
私は最初の答えに感謝しますが、ラムダアーキテクチャの使用を提唱することは、メタ問題の5倍のレベルを解決する優れた方法のように聞こえ、このアプローチの複雑さが本当に正当化されない限り、CRUDアプリを構築してシンプルに保つのではなく、決して実現しない可能性があります。最初から「かろうじて」スケールアウトするMongoDBについて投稿し、意味のある規模でMongoをすぐに殺すすべての書き込みの新しいレコードを提唱していることを思い出してください。これをCassandraセクションに移動します...
John Culviner 2017

1
この回答で提供された情報のおかげで、実際の削除の代わりにソフト削除を実行するために、実際にバックエンドのデザインを変更しました。それは本当に役立ついくつかのより深い知識を提供します。
ケナ

133

これは私がやったことです:

var ItemSchema = new Schema({
    name    : { type: String, required: true, trim: true }
  , created_at    : { type: Date }
  , updated_at    : { type: Date }
});


ItemSchema.pre('save', function(next){
  now = new Date();
  this.updated_at = now;
  if ( !this.created_at ) {
    this.created_at = now;
  }
  next();
});

8
1.現在の時刻をローカル変数に格納し、new Date()を呼び出すたびに割り当てるのではなく、これにより、最初のパスでcreated_atとupdated_atが同じexcect値を持つようになります。2. new Date => new Date()
Shay Erlichmen 2013年

13
ObjectIdを使用すると、そこからcreated_atを取得できることを指摘したいだけです。別のフィールドは必要ありません。チェックアウトgetTimestamp()
Xerri 2013年

6
created_atの他のオプションは、モデルを-> created_atに変更することです:{type:Date、default:Date.now}、
OscarVGG

1
@ajbrausスキーマプラグインを作成する
wlingke

2
静的メソッドDate.now()であるため、可能な限りnew Date高速ではなく使用する
karlkurzer

107

timestampsスキーマの組み込みオプションを使用します。

var ItemSchema = new Schema({
    name: { type: String, required: true, trim: true }
},
{
    timestamps: true
});

これは自動的に追加されますcreatedAtupdatedAt、あなたのスキーマにフィールド。

http://mongoosejs.com/docs/guide.html#timestamps


1
mongooseバージョン> = 4.0が必要
Jensen

2
私はドキュメントが不明確だと思います-これはフィールドを追加しますが、更新のたびに更新されることも確認しますか?
Ludwik、2016年

一般に、createdAtは常に1回だけ格納されます...オブジェクトが作成されたとき。updatedAt新しい保存ごとに更新されます(objが変更された場合)
codyc4321

1
この「2016-12-07T11:46:46.0​​66Z」を取得しました。タイムスタンプの形式、タイムゾーンの変更方法について教えてください。mongoDBサーバーのタイムゾーンを取得していますか?
Mahesh K

@mcompeau、回答ありがとうございます!長いショットだと思いますが、この方法で作成したフィールドをインデックスとして使用できるかどうか、覚えていますか?
マニドス2017

29

update()または使用する場合findOneAndUpdate()

{upsert: true}オプション

あなたは使うことができます $setOnInsert

var update = {
  updatedAt: new Date(),
  $setOnInsert: {
    createdAt: new Date()
  }
};

1
これはほとんどのmongoライブラリで機能します。受け入れられた回答への変更
16:12の

1
Mogoのデフォルト_idフィールドを使用している場合、createdAtフィールドは必要ありません。詳細については、以下の私の答えを確認してください。
Pavel Nikolov 2016

1
...私の元の回答を確認してください。
Pavel Nikolov 2016

25

追加timestampsあなたにSchema、このようにcreatedAtしてupdatedAt、あなたのために自動生成されます。

var UserSchema = new Schema({
    email: String,
    views: { type: Number, default: 0 },
    status: Boolean
}, { timestamps: {} });

ここに画像の説明を入力してください
また、あなたは変更することができますcreatedAt -> created_at

timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' }

2
Mongooseがこの作業をすべて代行してくれるようになったので、これが今のところ最良の解決策であることに同意します。
Vince Bowdren、2018年

ええ、その@VinceBowdrenに同意します
Mr.spShuvo

8

このようにして、作成および更新を行いました。

私のスキーマ内に、次のように作成および更新を追加しました。

   / **
     *記事のスキーマ
     * /
    var ArticleSchema = new Schema({
        作成した: {
            タイプ:日付、
            デフォルト:Date.now
        }、
        更新しました: {
            タイプ:日付、
            デフォルト:Date.now
        }、
        題名: {
            タイプ:文字列、
            デフォルト: ''、
            トリム:true、
            必須:「タイトルは空白にできません」
        }、
        コンテンツ:{
            タイプ:文字列、
            デフォルト: ''、
            トリム:真
        }、
        ユーザー:{
            タイプ:Schema.ObjectId、
            ref: 'ユーザー'
        }
    });

次に、追加した記事コントローラー内の記事更新メソッドで:

/ **
     *記事を更新する
     * /
    exports.update = function(req、res){
        var article = req.article;

        記事= _.extend(記事、req.body);
        article.set( "更新"、Date.now());

        article.save(function(err){
            もし(err){
                return res.status(400).send({
                    メッセージ:errorHandler.getErrorMessage(err)
                });
            } そうしないと {
                res.json(記事);
            }
        });
    };

太字のセクションは重要な部分です。



4

timestampプラグインを使用して、mongoose-troopこの動作を任意のスキーマに追加できます。


3

このプラグインは非常に簡単に使用できます。ドキュメントから:

var timestamps = require('mongoose-timestamp');
var UserSchema = new Schema({
    username: String
});
UserSchema.plugin(timestamps);
mongoose.model('User', UserSchema);
var User = mongoose.model('User', UserSchema)

また、必要に応じてフィールドの名前を設定します。

mongoose.plugin(timestamps,  {
  createdAt: 'created_at', 
  updatedAt: 'updated_at'
});

2

スキーマプラグインを使用してこれを実現することもできます

ではhelpers/schemaPlugin.js、ファイル

module.exports = function(schema) {

  var updateDate = function(next){
    var self = this;
    self.updated_at = new Date();
    if ( !self.created_at ) {
      self.created_at = now;
    }
    next()
  };
  // update date for bellow 4 methods
  schema.pre('save', updateDate)
    .pre('update', updateDate)
    .pre('findOneAndUpdate', updateDate)
    .pre('findByIdAndUpdate', updateDate);
};

そしてmodels/ItemSchema.jsファイルに:

var mongoose = require('mongoose'),
  Schema   = mongoose.Schema,
  SchemaPlugin = require('../helpers/schemaPlugin');

var ItemSchema = new Schema({
  name    : { type: String, required: true, trim: true },
  created_at    : { type: Date },
  updated_at    : { type: Date }
});
ItemSchema.plugin(SchemaPlugin);
module.exports = mongoose.model('Item', ItemSchema);

2

モデルスキーマで、属性タイムスタンプを追加し、次に示すように値にtrueを割り当てます。

var ItemSchema = new Schema({
   name :  { type: String, required: true, trim: true },
},{timestamps : true}
);

これは何をしますか?
chovy

タイムスタンプ属性は、各ドキュメントにcreated_atおよびupdated_atフィールドを追加します。Created_atフィールドはドキュメントの作成時刻を示し、updated_atフィールドはドキュメントの作成時刻がある場合は更新時刻を示します。両方のフィールド値はISO時間形式です。これがあなたの疑問を明らかにすることを願っています。
Pavneet Kaur

1
const mongoose = require('mongoose');
const config = require('config');
const util = require('util');

const Schema = mongoose.Schema;
const BaseSchema = function(obj, options) {
  if (typeof(options) == 'undefined') {
    options = {};
  }
  if (typeof(options['timestamps']) == 'undefined') {
    options['timestamps'] = true;
  }

  Schema.apply(this, [obj, options]);
};
util.inherits(BaseSchema, Schema);

var testSchema = new BaseSchema({
  jsonObject: { type: Object }
  , stringVar : { type: String }
});

これを使用できるため、すべてのテーブルにこのオプションを含める必要はありません。


1

私のマングースのバージョンは4.10.2です

フックのみfindOneAndUpdateが機能しているようです

ModelSchema.pre('findOneAndUpdate', function(next) {
  // console.log('pre findOneAndUpdate ....')
  this.update({},{ $set: { updatedAt: new Date() } });
  next()
})

0

関数を使用して、計算されたデフォルト値を返します。

var ItemSchema = new Schema({
    name: {
      type: String,
      required: true,
      trim: true
    },
    created_at: {
      type: Date,
      default: function(){
        return Date.now();
      }
    },
    updated_at: {
      type: Date,
      default: function(){
        return Date.now();
      }
    }
});

ItemSchema.pre('save', function(done) {
  this.updated_at = Date.now();
  done();
});

Date.now()関数をラップする必要はありません:...default: Date.now()
karlkurzer '05

1
テストで '.now()'をモックできるように、それを関数でラップします。それ以外の場合は、初期化中に1回だけ実行され、値を簡単に変更することはできません。
16

1
default: Date.now()間違っていることに注意してください。どちらかと言えばdefault: Date.now。そうでない場合、すべてのドキュメントのタイムスタンプは同じになります。アプリケーションが開始した時刻;)
Max Truxa

私はあなたのdefault: Date.now戦略が好きです。はるかにきれい。
16

0

私は実際にこれを後ろで行います

すべてが更新でうまくいく場合:

 // All ifs passed successfully. Moving on the Model.save
    Model.lastUpdated = Date.now(); // <------ Now!
    Model.save(function (err, result) {
      if (err) {
        return res.status(500).json({
          title: 'An error occured',
          error: err
        });
      }
      res.status(200).json({
        message: 'Model Updated',
        obj: result
      });
    });

0

machinepack-datetimeを使用して日時をフォーマットします。

tutorialSchema.virtual('createdOn').get(function () {
    const DateTime = require('machinepack-datetime');
    let timeAgoString = "";
    try {
        timeAgoString = DateTime.timeFrom({
            toWhen: DateTime.parse({
                datetime: this.createdAt
            }).execSync(),
            fromWhen: new Date().getTime()
        }).execSync();
    } catch(err) {
        console.log('error getting createdon', err);
    }
    return timeAgoString; // a second ago
});

マシンパックは、エクスプレスや一般的なJavaScriptの世界とは異なり、APIが明確で優れています。


-2

ミドルウェア仮想を使用できます。これはあなたのupdated_atフィールドの例です:

ItemSchema.virtual('name').set(function (name) {
  this.updated_at = Date.now;
  return name;
});

これは実際にいつ設定されますか?そしてそれは持続しますか?だから今から3日後、それはまだ3日前からの日付がありますか?
chovy

この場合、指定されたプロパティを変更するたびにvirtualが呼び出されますname。そして、はい、それは永続的でなければなりません。
zemirco

これはItemオブジェクトのすべてのフィールドで機能しますか?私はこの解決策が私が望んでいることを確信していない
12:10の
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.