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

Binarytales
sumber
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();
});
Pavel Nikolov
sumber
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();
});
kenyal
sumber
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

mcompeau
sumber
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()
  }
};
Roman Rhrn Nesterov
sumber
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' }
Phan Van Linh
sumber
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.

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

ItemSchema.set('timestamps', true); // this will add createdAt and updatedAt timestamps

Documents: https://mongoosejs.com/docs/guide.html#timestamps

Nikolay_R
sumber
Bagaimana Anda menambahkan Indeks pada bidang CreatedAt?
Valor_
4

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

JohnnyHK
sumber
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'
});
Orr
sumber
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);
Shaishab Roy
sumber
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}
);
Pavneet Kaur
sumber
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

Raghu
sumber
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()
})
John Xiao
sumber
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();
});
orourkedd
sumber
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
      });
    });
shuk
sumber
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.

Piyush Patel
sumber
-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;
});
zirirco
sumber
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