Mongoose plugin that saves documents history in JsonPatch format and SemVer format.
This is a Node.js module available through the npm registry. Installation is done using the npm install
command:
If using mongoose 4.x.x remove will only save if calling model.remove.Mongoose 5.x now applies middleware hooks for remove on both schema and model.
See https://mongoosejs.com/docs/middleware.html
$ npm install mongoose-history-plugin
import mongoose from 'mongoose';
import MongooseHistoryPlugin from 'mongoose-history-plugin';
mongoose.connect('mongodb://localhost/Default');
// Default options
let options = {
mongoose: mongoose, // A mongoose instance
userCollection: 'users', // Colletcion to ref when you pass an user id
userCollectionIdType: false, // Type for user collection ref id, defaults to ObjectId
accountCollection: 'accounts', // Collection to ref when you pass an account id or the item has an account property
accountCollectionIdType: false, // Type for account collection ref id, defaults to ObjectId
userFieldName: 'user', // Name of the property for the user
accountFieldName: 'account', // Name of the property of the account if any
timestampFieldName: 'timestamp', // Name of the property of the timestamp
methodFieldName: 'method', // Name of the property of the method
collectionIdType: false, // Cast type for _id (support for other binary types like uuid) defaults to ObjectId
ignore: [], // List of fields to ignore when compare changes
noDiffSave: false, // If true save event even if there are no changes
noDiffSaveOnMethods: ['delete'], // If a method is in this list, it saves history even if there is no diff.
noEventSave: true, // If false save only when __history property is passed
modelName: '__histories', // Name of the collection for the histories
embeddedDocument: false, // Is this a sub document
embeddedModelName: '', // Name of model if used with embedded document
// If true save only the _id of the populated fields
// If false save the whole object of the populated fields
// If false and a populated field property changes it triggers a new history
// You need to populate the field after a change is made on the original document or it will not catch the differences
ignorePopulatedFields: true
};
// Add the plugin to the schema with default options
let Schema = mongoose.Schema({ name: 'string', size: 'string' });
Schema.plugin(MongooseHistoryPlugin(options));
// Create a model
let Tank = mongoose.model('tank', Schema);
// Create a document
let small = new Tank({
size: 'small',
// History property is optional by default
__history: {
event: 'created',
user: undefined, // An object id of the user that generate the event
reason: undefined,
data: undefined, // Additional data to save with the event
type: undefined, // One of 'patch', 'minor', 'major'. If undefined defaults to 'major'
method: 'newTank' // Optional and intended for method reference
}
});
small
.save()
.then((small) => {
small.name = 'Small tank';
// History property is optional by default
small.__history = {
event: 'updated',
user: undefined,
reason: undefined,
data: undefined,
type: undefined,
method: 'updateTank'
};
return small.save();
})
.then((small) => {
// Create another history version
small.name = 'Smallest tank';
// History property is optional by default
small.__history = {
event: 'updated',
user: undefined,
reason: undefined,
data: undefined,
type: undefined,
method: 'updateTank'
};
return small.save();
})
.then((small) => {
// All options are optional
let query = {
find: {}, // Must be an object
select: {}, // Must be an object
sort: '',
populate: '',
limit: 20
};
// Get the diff histories in JsonDiffPatch format
small.getDiffs(query).then(console.log);
/*
[
{
version: '2.0.0',
diff: { name: ['Small tank', 'Smallest tank'] },
event: 'updated',
method: 'updateTank',
timestamp: 2019-08-24T12:04:15.253Z },
{
version: '1.0.0',
diff: { name: [ 'Small tank' ] },
event: 'updated',
method: 'updateTank',
timestamp: 2019-08-24T12:04:15.253Z },
{
version: '0.0.0',
diff: { _id: [ '5d6127bf3a50db72bc8cbed2' ], size: [ 'small' ] },
event: 'created',
method: 'newTank',
timestamp: 2019-08-24T12:04:15.157Z
}
]
*/
// Get a diff history in JsonDiffPatch format
small.getDiff('1.0.0').then(console.log);
/*
{
_id: 5d6127bf3a50db72bc8cbed4,
version: '1.0.0',
collectionName: 'tank6',
collectionId: 5d6127bf3a50db72bc8cbed2,
diff: { name: [ 'Small tank' ] },
event: 'updated',
method: 'updateTank',
timestamp: 2019-08-24T12:04:15.253Z
}
*/
// Get the versions
small.getVersions(query).then(console.log);
/*
[
{
version: '2.0.0',
event: 'updated',
method: 'updateTank',
timestamp: expect.any(Date),
object: { name: 'Smallest tank' }
},
{
version: '1.0.0',
event: 'updated',
method: 'updateTank',
timestamp: 2019-08-24T12:04:15.253Z,
object: { name: 'Small tank' }
},
{
version: '0.0.0',
event: 'created',
method: 'newTank',
timestamp: 2019-08-24T12:04:15.157Z,
object: {
name: 'Small tank',
_id: '5d6127bf3a50db72bc8cbed2',
size: 'small'
}
}
]
*/
// Get a version
small.getVersion('1.0.0').then(console.log);
/*
{
_id: 5d6127bf3a50db72bc8cbed4,
version: '1.0.0',
collectionName: 'tank6',
collectionId: 5d6127bf3a50db72bc8cbed2,
event: 'updated',
method: 'updateTank',
timestamp: 2019-08-24T12:04:15.253Z,
object: {
_id: '5d6127bf3a50db72bc8cbed2',
size: 'small',
name: 'Small tank'
}
}
*/
// Compare two versions
small.compareVersions('0.0.0', '1.0.0').then(console.log);
/*
{
diff: { name: [ 'Small tank' ] },
left: { _id: '5d6127bf3a50db72bc8cbed2', size: 'small' },
right: {
_id: '5d6127bf3a50db72bc8cbed2',
size: 'small',
name: 'Small tank'
}
}
*/
});
small
.remove()
.then((small) => {
small.__history = {
event: 'removed',
user: undefined,
reason: undefined,
data: undefined,
type: undefined,
method: 'delete'
};
return small.remove();
})
.then((small) => {
// All options are optional
let query = {
find: {}, // Must be an object
select: {}, // Must be an object
sort: '',
populate: '',
limit: 20
};
// Get the diff histories in JsonDiffPatch format
small.getDiffs(query).then(console.log);
// Get a diff history in JsonDiffPatch format
small.getDiff('2.0.0').then(console.log);
// Get the versions
small.getVersions(query).then(console.log);
// Get a version
small.getVersion('2.0.0').then(console.log);
// Compare two versions
// In the case of delete, the diff is empty because the object is not changed.
small.compareVersions('1.0.0', '2.0.0').then(console.log);
});
// Add the plugin to many schemas with a single history collection
let plugin = MongooseHistoryPlugin(options);
Schema.plugin(plugin);
AnotherSchema.plugin(plugin);
// Add the plugin with a dedicated history collection for every schema
Schema.plugin(
MongooseHistoryPlugin(
Object.assign({}, options, { modelName: 'collectionName_versions' })
)
);
AnotherSchema.plugin(
MongooseHistoryPlugin(
Object.assign({}, options, { modelName: 'anotherCollectionName_versions' })
)
);
Returns an array of all the histories of the document. You can pass a options object that will be passed to a collection find method.
The returned objects within the array have the next shape:
{
version, // The version of the document according to the SemVer format
diff, // Changes made in this version diffed against the previous version and according to the JsonPatch format
event, // The event that create this version if any
method, // The name of the method that create this version if any
timestamp // The timestamp in which this version was created
}
Returns the version history for this document.
The returned object has the next shape:
{
_id, // ObjectId for this history
version, // The version of the document according to the SemVer format
collectionName, // Name of the collection that belongs to this document
collectionId, // ObjectId of the document
diff, // Changes made in this version diffed against the previous version and according to the JsonPatch format
event, // The event that create this version if any
method, // The name of the method that create this version if any
timestamp // The timestamp in which this version was created
}
Returns an array of all the versions of the document. You can pass a options object that will be passed to a collection find method.
The returned objects within the array have the next shape:
{
version, // The version of the document according to the SemVer format
event, // The event that create this version if any
method, // The name of the method that create this version if any
timestamp // The timestamp in which this version was created
object // Object with the properties changed in this version diffed against the previous version
}
Returns the document as it was at the time of this version.
The returned object has the next shape:
{
_id, // ObjectId for this history
version, // The version of the document according to the SemVer format
collectionName, // Name of the collection that belongs to this document
collectionId, // ObjectId of the document
event, // The event that create this version if any
method, // The name of the method that create this version if any
timestamp, // The timestamp in which this version was created
object // The complete object as it was at this version
}
Returns the differences between two versions of the document.
The returned object has the next shape:
{
diff, // The differences between the two versions according to the JsonPatch format
left, // The document as it was at the left version
right // The document as it was at the right version
}
npm test
For development use npm dev:test
Author: Masquerade Circus. License Apache-2.0
(1) proxy 前端的端口在:localhost:3000 后端的端口在:localhost:1234 所以要在webpack中配置proxy选项 (proxy是代理的意思) 在package.json中添加如下配置-------这里用的是create-react-app脚手架eject后的项目 "proxy":"http://localhost:1234" // 把前端的请求都代理到123
Burp Proxy History The Proxy history maintains a full record of all messages that have passed through the Proxy. You can filter and annotate this information to help manage it, and also use the Proxy
history 用法 Usage: docker history [OPTIONS] IMAGE Show the history of an image -H, --human=true Print sizes and dates in human readable format --help=false Print usage --no-trunc=false
Apart from various contributions, WinSCP is mostly a one-man project. The man is me, Martin Prikryl. The following is a list of project milestones. See also version history. I started the first work o
I worked a lot on the Dojo Loader. The normal dojo loader used to use synchronous XMLHttpRequest (XHR) calls. However, the XHR loader couldn't load Dojo modules from other domains because of the same-
封装了对历史记录的操作,实现浏览器页面间前进后退的功能。 标题 内容 类型 动态内容 支持布局 responsive, fixed-height, fill, container, fixed 所需脚本 https://c.mipcdn.com/static/v2/mip-history/mip-history.js 示例 基本用法 <mip-history history="go, -1" cl
Shell History Inspired by bamos/zsh-history-analysis. Visualize your usage of Bash/Zsh through a web appthanks to Flask and Highcharts! Duration Length Type Exit code Hourly Daily Over time Markov cha