tambahkan bidang Created_at dan updated_at ke skema luwak


166

Apakah ada cara untuk menambahkan bidang create_at dan updated_at ke skema luwak, tanpa harus meneruskannya di setiap kali MyModel baru () dipanggil?

Bidang create_at akan menjadi tanggal dan hanya ditambahkan ketika dokumen dibuat. Bidang updated_at akan diperbarui dengan tanggal baru setiap kali save () dipanggil pada dokumen.

Saya telah mencoba ini dalam skema saya, tetapi bidang tidak muncul kecuali jika saya menambahkannya:

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

Saya melakukan persis apa yang Anda lakukan dan itu berhasil. Menggunakan Mongoose 4.8.4. Mungkinkah hal baru?
martinedwards

1
ini dari beberapa waktu yang lalu.
chovy

Ya, pikir itu layak dicatat bahwa di atas sekarang berfungsi.
martinedwards

Jawaban:


132

Mulai dari Mongoose 4.0 Anda sekarang dapat mengatur opsi cap waktu pada Skema agar Mongoose menangani ini untuk Anda:

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

Anda dapat mengubah nama bidang yang digunakan seperti ini:

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

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


2
Setuju, ini adalah opsi terbaik dalam Mongoose 4.0.
Tadd Giles

258

PEMBARUAN: (5 tahun kemudian)

Catatan: Jika Anda memutuskan untuk menggunakan Arsitektur Kappa ( Pengadaan Acara + CQRS ), maka Anda tidak perlu tanggal yang diperbarui sama sekali. Karena data Anda adalah log peristiwa yang tidak berubah dan hanya-tambahkan, Anda hanya perlu tanggal yang dibuat acara. Mirip dengan Arsitektur Lambda , dijelaskan di bawah ini. Maka status aplikasi Anda adalah proyeksi log peristiwa (data yang diturunkan). Jika Anda menerima acara berikutnya tentang entitas yang ada, maka Anda akan menggunakan tanggal yang dibuat acara itu sebagai tanggal yang diperbarui untuk entitas Anda. Ini adalah praktik yang biasa digunakan (dan biasanya disalahpahami) dalam sistem layanan mikro.

PEMBARUAN: (4 tahun kemudian)

Jika Anda menggunakan bidang ObjectIdAnda _id(yang biasanya merupakan kasus), maka yang perlu Anda lakukan adalah:

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

Lihat jawaban asli saya di bawah ini tentang cara mendapatkan cap waktu yang dibuat dari _idbidang. Jika Anda perlu menggunakan ID dari sistem eksternal, maka periksa jawaban Roman Rhrn Nesterov.

UPDATE: (2,5 tahun kemudian)

Anda sekarang dapat menggunakan opsi #timestamps dengan versi luwak> = 4.0.

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

Jika mengatur cap waktu, luak menetapkan createdAtdan updatedAtbidang ke skema Anda, tipe yang ditugaskan adalah Date.

Anda juga dapat menentukan nama timestamp yang diajukan:

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

Catatan: Jika Anda bekerja pada aplikasi besar dengan data penting, Anda harus mempertimbangkan kembali memperbarui dokumen Anda. Saya akan menyarankan Anda untuk bekerja dengan data yang tidak dapat diubah, append-only ( arsitektur lambda ). Artinya, Anda hanya mengizinkan sisipan. Pembaruan dan penghapusan tidak boleh diizinkan! Jika Anda ingin "menghapus" catatan, Anda dapat dengan mudah memasukkan versi baru dokumen dengan beberapa timestamp/ version diajukan dan kemudian setel deletedbidang ke true. Demikian pula jika Anda ingin memperbarui dokumen - Anda membuat yang baru dengan bidang yang sesuai diperbarui dan sisa bidang disalin. Kemudian untuk meminta dokumen ini Anda akan mendapatkan yang dengan cap waktu terbaru atau versi tertinggi yang bukan "dihapus" (thedeleted bidang tidak terdefinisi atau salah`).

Ketidakberesan data memastikan bahwa data Anda dapat dibantah - Anda dapat melacak sejarah setiap dokumen. Anda juga dapat mengembalikan ke versi dokumen sebelumnya jika terjadi kesalahan. Jika Anda pergi dengan arsitektur seperti ObjectId.getTimestamp()itu yang Anda butuhkan, dan itu tidak bergantung pada luwak.


JAWABAN ASLI:

Jika Anda menggunakan ObjectId sebagai bidang identitas Anda, Anda tidak perlu created_atbidang. ObjectIds memiliki metode yang disebut getTimestamp().

ObjectId ("507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

Ini akan mengembalikan output berikut:

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

Info lebih lanjut di sini Bagaimana cara mengekstrak tanggal yang dibuat dari Mongo ObjectID

Untuk menambahkan updated_atarsip, Anda harus menggunakan ini:

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
Bagaimana Anda melakukannya di Mongoose / node.js?
Zebra Propulsion Lab

6
Itu layak untuk diketahui meskipun itu bukan solusi yang digunakan, sangat menarik!
tanpa disadari

Tetapi jika saya ingin meneruskan buat pada tanggal ke tampilan, saya perlu mengatur variabel khusus untuk ini, atau lulus id kan?

3
Saya menghargai jawaban awal tetapi menganjurkan untuk menggunakan arsitektur lambda juga terdengar seperti cara yang bagus untuk memecahkan 5x tingkat masalah meta dan mungkin tidak pernah memberikan daripada membangun aplikasi CRUD dan menjaganya tetap sederhana kecuali kompleksitas pendekatan ini benar-benar dijamin. Ingat Anda memposting tentang MongoDB yang awalnya hanya berskala dan Anda menganjurkan untuk catatan baru untuk setiap penulisan yang akan dengan cepat membunuh Mongo pada skala yang berarti. Pindahkan ini ke bagian Cassandra ...
John Culviner

1
Saya benar-benar mengubah desain backend saya untuk melakukan penghapusan lunak di tempat penghapusan nyata, berkat informasi yang diberikan dalam jawaban ini. Ini memberikan beberapa pengetahuan yang lebih dalam yang sangat berguna.
Kenna

133

Inilah yang akhirnya saya lakukan:

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. Simpan waktu saat ini di var lokal dan tetapkan alih-alih setiap kali memanggil Date baru (), ini akan memastikan bahwa pada pass pertama create_at dan updated_at memiliki nilai excect yang sama. 2. Tanggal baru => Tanggal baru ()
Shay Erlichmen

13
Hanya ingin menunjukkan bahwa jika Anda menggunakan ObjectId maka Anda bisa mendapatkan create_at dari sana .... Anda tidak perlu bidang yang terpisah. LihatgetTimestamp()
Xerri

6
Opsi lain untuk Created_at dapat mengubah model menjadi -> Created_at: {type: Date, default: Date.now},
OscarVGG

1
@ajbraus Buat plugin skema
wlingke

2
juga gunakan Date.now()jika memungkinkan alih-alih new Datelebih cepat karena merupakan metode statis
karlkurzer

107

Gunakan timestampsopsi bawaan untuk Skema Anda.

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

Ini akan secara otomatis menambahkan createdAtdan updatedAtbidang ke skema Anda.

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


1
Membutuhkan versi luwak> = 4.0
Jensen

2
Saya menemukan dokumen tidak jelas - ini menambahkan bidang, tetapi apakah itu juga memastikan mereka diperbarui pada setiap pembaruan?
Ludwik

umumnya, CreatedAt selalu hanya disimpan satu kali ... saat objek dibuat. updatedAtdiperbarui pada setiap save baru (ketika obj diubah)
codyc4321

1
Saya mendapatkan ini "2016-12-07T11: 46: 46.066Z" .. Bisakah tolong jelaskan format cap waktu, bagaimana mengubah zona waktu ?? dapat mengambil zona waktu server mongoDB ??
Mahesh K

@ micompeau, Terima kasih atas jawabannya! Saya tahu ini sangat sulit, tetapi apakah Anda ingat bahwa jika bidang yang dibuat dengan cara ini dapat digunakan sebagai indeks?
manidos

29

Jika menggunakan update()ataufindOneAndUpdate()

dengan {upsert: true}opsi

kamu bisa memakai $setOnInsert

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

1
ini bekerja di sebagian besar perpustakaan mongo. berubah menjadi jawaban yang diterima
chovy

1
Jika Anda menggunakan _idbidang default Mogo , maka Anda tidak perlu createdAtbidang. Periksa jawaban saya di bawah ini untuk perincian lebih lanjut.
Pavel Nikolov

1
... periksa JAWABAN ASLI saya .
Pavel Nikolov

25

Tambahkan timestampske Anda Schemaseperti ini lalu createdAtdan updatedAtakan menghasilkan otomatis untuk Anda

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

masukkan deskripsi gambar di sini
Anda juga dapat mengubahnya createdAt -> created_atdengan

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

2
Sekarang si luwak melakukan semua ini untuk Anda, saya setuju bahwa ini adalah solusi terbaik sekarang.
Vince Bowdren

Ya, Setujuilah @VinceBowdren
Mr.spShuvo

8

Inilah yang saya capai setelah dibuat dan diperbarui.

Di dalam skema saya, saya menambahkan yang dibuat dan diperbarui seperti:

   / **
     * Skema Artikel
     * /
    var ArticleSchema = Skema baru ({
        dibuat: {
            jenis: Tanggal,
            default: Date.now
        },
        diperbarui: {
            jenis: Tanggal,
            default: Date.now
        },
        judul: {
            jenis: String,
            bawaan: '',
            trim: benar,
            diperlukan: 'Judul tidak boleh kosong'
        },
        kandungan: {
            jenis: String,
            bawaan: '',
            trim: benar
        },
        pengguna: {
            ketik: Skema.ObjectId,
            ref: 'Pengguna'
        }
    });

Kemudian dalam metode pembaruan artikel saya di dalam pengontrol artikel saya menambahkan:

/ **
     * Perbarui artikel
     * /
    exports.update = function (req, res) {
        var article = req.article;

        article = _.extend (article, req.body);
        article.set ("updated", Date.now ());

        article.save (fungsi (err) {
            if (err) {
                return res.status (400) .send ({
                    pesan: errorHandler.getErrorMessage (err)
                });
            } lain {
                res.json (artikel);
            }
        });
    };

Bagian tebal adalah bagian yang menarik.



4

Anda dapat menggunakan timestampplugin mongoose-troopuntuk menambahkan perilaku ini ke skema apa pun.


3

Anda dapat menggunakan plugin ini dengan sangat mudah. Dari dokumen:

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

Dan juga mengatur nama bidang jika Anda ingin:

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

2

kita dapat mencapai ini dengan menggunakan plugin skema juga.

Dalam helpers/schemaPlugin.jsfile

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);
};

dan dalam models/ItemSchema.jsfile:

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

Dalam skema model Anda, cukup tambahkan stempel waktu atribut dan berikan nilai true padanya seperti yang ditunjukkan: -

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

Apa yang akan dilakukan?
chovy

Atribut timestamp akan menambahkan bidang Created_at dan updated_at di setiap dokumen. Bidang Created_at menunjukkan waktu pembuatan dokumen dan bidang updated_at menunjukkan waktu pembaruan jika ada waktu pembuatan dokumen. Nilai kedua bidang dalam format waktu ISO. Semoga ini menghapus keraguan Anda Chovy.
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 }
});

Sekarang Anda dapat menggunakan ini, sehingga tidak perlu menyertakan opsi ini di setiap tabel


1

Versi luwak saya adalah 4.10.2

Sepertinya hanya kail findOneAndUpdateyang berfungsi

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

0

Gunakan fungsi untuk mengembalikan nilai default yang dihitung:

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();
});

tidak perlu untuk membungkus Date.now()dalam suatu fungsi cukup lakukan:...default: Date.now()
karlkurzer

1
Saya membungkusnya dalam suatu fungsi sehingga saya bisa mengejek '.sekarang ()' dalam tes. Kalau tidak, itu hanya dijalankan sekali selama inisialisasi dan nilainya tidak dapat dengan mudah diubah.
orourkedd

1
Perhatikan itu default: Date.now()salah. Jika ada itu default: Date.now. Kalau tidak, semua dokumen Anda akan memiliki stempel waktu yang sama: Waktu ketika aplikasi Anda dimulai;)
Max Truxa

Saya suka default: Date.nowstrategi Anda . lebih bersih.
orourkedd

0

Saya sebenarnya melakukan ini di belakang

Jika semuanya berjalan baik dengan pembaruan:

 // 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

Gunakan machinepack-datetime untuk memformat 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
});

Paket mesin sangat bagus dengan API yang jelas tidak seperti dunia Javascript ekspres atau umum.


-2

Anda dapat menggunakan middleware dan virtual . Ini adalah contoh untuk updated_atbidang Anda :

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

Kapan ini benar-benar siap? dan apakah itu akan bertahan? Jadi 3 hari dari sekarang, masih akan ada tanggal dari 3 hari yang lalu?
chovy

virtual akan dipanggil setiap kali Anda mengubah properti yang diberikan, dalam hal ini name. Dan ya, itu harus gigih.
zemirco

apakah ini akan bekerja untuk semua bidang pada objek Item? Saya tidak yakin solusi ini melakukan apa yang saya inginkan
chovy
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.