thêm các trường created_at và update_at vào lược đồ mongoose


166

Có cách nào để thêm các trường created_at và update_at vào lược đồ mongoose mà không phải chuyển chúng trong mỗi lần MyModel () mới được gọi không?

Trường created_at sẽ là một ngày và chỉ được thêm khi tài liệu được tạo. Trường update_at sẽ được cập nhật với ngày mới bất cứ khi nào save () được gọi trên tài liệu.

Tôi đã thử điều này trong lược đồ của mình, nhưng trường không hiển thị trừ khi tôi thêm nó vào:

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

Tôi đã làm chính xác những gì bạn đã làm và nó đã làm việc. Sử dụng Mongoose 4.8.4. Có thể là một điều mới?
liệt kê vào

1
điều này là từ khá lâu trước đây.
chovy

Vâng, nghĩ rằng đáng chú ý là bây giờ hoạt động.
martinedwards

Câu trả lời:


132

Kể từ Mongoose 4.0, giờ đây bạn có thể đặt tùy chọn dấu thời gian trên Schema để Mongoose xử lý việc này cho bạn:

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

Bạn có thể thay đổi tên của các trường được sử dụng như vậy:

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

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


2
Đồng ý, đây là lựa chọn tốt nhất trong Mongoose 4.0.
Tadd Giles

258

CẬP NHẬT: (5 năm sau)

Lưu ý: Nếu bạn quyết định sử dụng Kiến trúc Kappa ( Tìm nguồn cung cấp sự kiện + CQRS ), thì bạn hoàn toàn không cần cập nhật. Vì dữ liệu của bạn là nhật ký sự kiện không thay đổi, chỉ nối thêm, nên bạn chỉ cần ngày tạo sự kiện. Tương tự như Kiến trúc Lambda , được mô tả dưới đây. Sau đó, trạng thái ứng dụng của bạn là hình chiếu của nhật ký sự kiện (dữ liệu dẫn xuất). Nếu bạn nhận được một sự kiện tiếp theo về thực thể hiện có, thì bạn sẽ sử dụng ngày được tạo của sự kiện đó làm ngày cập nhật cho thực thể của mình. Đây là một thực tế thường được sử dụng (và thường bị hiểu lầm) trong các hệ thống miceroservice.

CẬP NHẬT: (4 năm sau)

Nếu bạn sử dụng ObjectIdlàm _idlĩnh vực của mình (thường là như vậy), thì tất cả những gì bạn cần làm là:

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

Kiểm tra câu trả lời ban đầu của tôi dưới đây về cách lấy dấu thời gian đã tạo từ _idtrường. Nếu bạn cần sử dụng ID từ hệ thống bên ngoài, hãy kiểm tra câu trả lời của Roman Rhrn Nesterov.

CẬP NHẬT: (2,5 năm sau)

Bây giờ bạn có thể sử dụng tùy chọn #timestamp với phiên bản mongoose> = 4.0.

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

Nếu đặt dấu thời gian, mongoose gán createdAtupdatedAtcác trường cho lược đồ của bạn, loại được gán là Date.

Bạn cũng có thể chỉ định tên của dấu thời gian:

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

Lưu ý: Nếu bạn đang làm việc trên một ứng dụng lớn có dữ liệu quan trọng, bạn nên xem xét lại việc cập nhật tài liệu của mình. Tôi sẽ khuyên bạn nên làm việc với dữ liệu bất biến, chỉ bổ sung ( kiến trúc lambda ). Điều này có nghĩa là bạn chỉ bao giờ cho phép chèn. Cập nhật và xóa không nên được cho phép! Nếu bạn muốn "xóa" một bản ghi, bạn có thể dễ dàng chèn một phiên bản mới của tài liệu với một số timestamp/ version nộp và sau đó đặt một deletedtrường thành true. Tương tự như vậy nếu bạn muốn cập nhật một tài liệu - bạn tạo một tài liệu mới với các trường thích hợp được cập nhật và phần còn lại của các trường được sao chép. Sau đó, để truy vấn tài liệu này, bạn sẽ nhận được một tài liệu có dấu thời gian mới nhất hoặc phiên bản cao nhất không "xóa" (deleted trường không xác định hoặc sai`).

Tính không thay đổi dữ liệu đảm bảo rằng dữ liệu của bạn có thể gỡ lỗi - bạn có thể theo dõi lịch sử của mọi tài liệu. Bạn cũng có thể quay lại phiên bản trước của tài liệu nếu có sự cố. Nếu bạn đi với một kiến ​​trúc như vậy ObjectId.getTimestamp()là tất cả những gì bạn cần, và nó không phụ thuộc vào Mongoose.


TRẢ LỜI GỐC:

Nếu bạn đang sử dụng ObjectId làm trường nhận dạng, bạn không cần created_attrường. ObjectIds có một phương thức gọi là getTimestamp().

ObjectId ("507c7f79bcf86cd7994f6c0e"). GetTimestamp ()

Điều này sẽ trả về đầu ra sau:

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

Thông tin thêm ở đây Làm cách nào để trích xuất ngày đã tạo ra khỏi Mongo ObjectID

Để thêm updated_attệp bạn cần sử dụng:

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
Làm thế nào để bạn làm điều đó trong Mongoose / node.js?
Phòng thí nghiệm sức đẩy Zebra

6
Điều đó đáng để biết ngay cả khi đó không phải là giải pháp được sử dụng, rất thú vị!
không mong muốn

Nhưng nếu tôi muốn chuyển tạo vào ngày để xem, tôi sẽ cần đặt biến đặc biệt cho điều này, hoặc chuyển id phải không?

3
Tôi đánh giá cao câu trả lời ban đầu nhưng ủng hộ việc sử dụng kiến ​​trúc lambda nghe có vẻ như là một cách tuyệt vời để giải quyết các vấn đề meta cấp độ 5x và có thể không bao giờ cung cấp thay vì xây dựng ứng dụng CRUD và giữ cho nó đơn giản trừ khi sự phức tạp của phương pháp này thực sự được bảo đảm. Hãy nhớ rằng bạn đang đăng bài về MongoDB, cái mà hầu như không có quy mô bắt đầu và bạn đang ủng hộ một bản ghi mới cho mỗi bài viết sẽ nhanh chóng giết Mongo ở bất kỳ quy mô có ý nghĩa nào. Di chuyển phần này đến phần Cassandra ...
John Culviner

1
Tôi thực sự đã thay đổi thiết kế phụ trợ của mình để thực hiện xóa mềm thay cho xóa thực, nhờ vào thông tin được cung cấp trong câu trả lời này. Nó cung cấp một số kiến ​​thức sâu hơn mà thực sự hữu ích.
Kenna

133

Đây là những gì tôi đã làm:

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. Lưu trữ thời gian hiện tại trong một var cục bộ và gán nó thay vì mỗi lần gọi Date mới (), điều này sẽ đảm bảo rằng ở lần đầu tiên pass created_at và update_at có cùng giá trị kích thích. 2. Ngày mới => Ngày mới ()
Shay Erlichmen

13
Tôi muốn chỉ ra rằng nếu bạn sử dụng ObjectId thì bạn có thể lấy created_at từ đó .... bạn không cần một trường riêng. Kiểm tragetTimestamp()
Xerri

6
Tùy chọn khác cho created_at có thể là thay đổi mô hình thành -> created_at: {type: Date, default: Date.now},
OscarVGG

1
@ajbraus Tạo một plugin lược đồ
wlingke

2
cũng sử dụng Date.now()khi có thể thay vì new Datenhanh hơn vì đây là phương pháp tĩnh
karlkurzer

107

Sử dụng timestampstùy chọn tích hợp cho Schema của bạn.

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

Điều này sẽ tự động thêm createdAtupdatedAtcác trường vào lược đồ của bạn.

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


1
Yêu cầu phiên bản cầy mangut> = 4.0
Jensen

2
Tôi thấy các tài liệu không rõ ràng - điều này thêm các trường, nhưng nó cũng đảm bảo chúng được cập nhật trên mỗi bản cập nhật?
Ludwik

nói chung, createdAt luôn chỉ được lưu trữ một lần ... khi đối tượng được tạo. updatedAtđược cập nhật trên mỗi lần lưu mới (khi obj được thay đổi)
codyc4321

1
Tôi đã nhận được "2016-12-07T11: 46: 46.066Z" .. Xin vui lòng giải thích định dạng tem thời gian, cách thay đổi múi giờ ?? mất múi giờ máy chủ mongoDB ??
Mahesh K

@mcompeau, Cảm ơn bạn đã trả lời! Tôi biết đó là một cú sút xa, nhưng bạn có nhớ bất kỳ trường hợp nào nếu các trường được tạo theo cách này có thể được sử dụng làm chỉ mục không?
manidos

29

Nếu sử dụng update()hoặcfindOneAndUpdate()

với {upsert: true}tùy chọn

bạn có thể dùng $setOnInsert

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

1
điều này hoạt động trong hầu hết các thư viện mongo. thay đổi thành câu trả lời được chấp nhận
chovy

1
Nếu bạn đang sử dụng _idtrường mặc định của Mogo , thì bạn không cần một createdAttrường. Kiểm tra câu trả lời của tôi dưới đây để biết thêm chi tiết.
Pavel Nikolov

1
... kiểm tra TRẢ LỜI GỐC của tôi .
Pavel Nikolov

25

Thêm timestampsvào Schemanhư thế này sau đó createdAtupdatedAtsẽ tự động tạo cho bạn

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

nhập mô tả hình ảnh ở đây
Ngoài ra, bạn có thể thay đổi createdAt -> created_atbởi

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

2
Bây giờ Mongoose làm tất cả công việc này cho bạn, tôi đồng ý rằng đây là giải pháp tốt nhất hiện nay.
Vince Bowdren

Vâng, đồng ý với điều đó @VinceBowdren
Mr.spShuvo

8

Đây là cách tôi đạt được khi tạo và cập nhật.

Trong lược đồ của tôi, tôi đã thêm phần được tạo và cập nhật như vậy:

   / **
     * Điều Schema
     * /
    var ArticleSchema = Schema mới ({
        tạo: {
            loại: Ngày,
            mặc định: Date.now
        },
        đã cập nhật: {
            loại: Ngày,
            mặc định: Date.now
        },
        tiêu đề: {
            loại: Chuỗi,
            mặc định: '',
            cắt: đúng,
            bắt buộc: 'Tiêu đề không thể để trống'
        },
        Nội dung: {
            loại: Chuỗi,
            mặc định: '',
            cắt: đúng
        },
        người sử dụng: {
            loại: Schema.ObjectId,
            tham chiếu: 'Người dùng'
        }
    });

Sau đó, trong phương pháp cập nhật bài viết của tôi bên trong trình điều khiển bài viết tôi đã thêm:

/ **
     * Cập nhật một bài viết
     * /
    export.update = function (req, res) {
        bài viết var = req.article;

        bài viết = _.extend (bài báo, req.body);
        article.set ("đã cập nhật", Date.now ());

        article.save (hàm (err) {
            nếu (lỗi) {
                trả lại res.status (400) .send ({
                    tin nhắn: errorHandler.getErrorMessage (err)
                });
            } khác {
                res.json (bài viết);
            }
        });
    };

Các phần in đậm là những phần quan tâm.



4

Bạn có thể sử dụng timestampplugin của mongoose-troopđể thêm hành vi này vào bất kỳ lược đồ nào.


3

Bạn có thể sử dụng plugin này rất dễ dàng. Từ các tài liệu:

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

Và cũng đặt tên của các trường nếu bạn muốn:

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

2

chúng ta có thể đạt được điều này bằng cách sử dụng plugin lược đồ .

Trong helpers/schemaPlugin.jstập tin

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

và trong models/ItemSchema.jshồ sơ:

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

Trong lược đồ mô hình của bạn, chỉ cần thêm dấu thời gian thuộc tính và gán giá trị đúng cho nó như được hiển thị: -

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

Điều này sẽ làm gì?
chovy

Thuộc tính dấu thời gian sẽ thêm các trường created_at và update_at trong mỗi tài liệu. Trường created_at cho biết thời gian tạo tài liệu và trường update_at cho biết thời gian cập nhật nếu có thời gian tạo tài liệu khác. Cả hai giá trị trường đều ở định dạng thời gian ISO. Hy vọng điều này rõ ràng nghi ngờ của bạn 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 }
});

Bây giờ bạn có thể sử dụng cái này, do đó không cần đưa tùy chọn này vào mỗi bảng


1

Phiên bản cầy mangut của tôi là 4.10.2

Có vẻ như chỉ có móc findOneAndUpdatelà làm việc

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

0

Sử dụng hàm để trả về giá trị mặc định được tính:

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

không cần phải bọc Date.now()chức năng chỉ cần làm:...default: Date.now()
karlkurzer

1
Tôi gói nó trong một hàm để tôi có thể giả định '.now ()' trong các bài kiểm tra. Mặt khác, nó chỉ chạy một lần trong khi khởi tạo và giá trị không thể dễ dàng thay đổi.
orourkedd

1
Lưu ý rằng default: Date.now()sẽ sai. Nếu bất cứ điều gì đó là default: Date.now. Nếu không, tất cả các tài liệu của bạn sẽ có cùng dấu thời gian: Thời gian khi ứng dụng của bạn bắt đầu;)
Max Truxa

Tôi thích default: Date.nowchiến lược của bạn . sạch sẽ hơn nhiều
orourkedd

0

Tôi thực sự làm điều này ở phía sau

Nếu mọi việc suôn sẻ với việc cập nhật:

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

Sử dụng machinepack-datetime để định dạng 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
});

Gói máy rất tuyệt vời với API rõ ràng không giống như thế giới Javascript rõ ràng hoặc chung.


-2

Bạn có thể sử dụng phần mềm trung gianảo . Đây là một ví dụ cho updated_atlĩnh vực của bạn :

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

Khi nào thì điều này thực sự được thiết lập? và nó sẽ tồn tại? Vậy 3 ngày kể từ bây giờ, nó vẫn sẽ có một ngày từ 3 ngày trước?
chovy

ảo sẽ được gọi bất cứ khi nào bạn thay đổi thuộc tính đã cho, trong trường hợp này name. Và vâng, nó nên được kiên trì.
zemirco

điều này sẽ làm việc cho tất cả các trường trên đối tượng Item? Tôi không chắc giải pháp này làm được điều tôi muốn
chovy
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.