Database Manual / Data Modeling / Schema Design Patterns / Versioning

Keep a History of Document Versions保留文档版本的历史记录

When your data changes, some applications require that older versions of your data are kept available. In the Document Versioning Pattern, older data versions are retained in a separate collection from the current data.当数据发生变化时,一些应用程序要求保留旧版本的数据。在文档版本控制模式中,旧数据版本与当前数据保留在单独的集合中。

The Document Versioning Pattern lets you keep current documents and their history in the same database, and avoid having to use multiple systems to manage data history.文档版本控制模式允许您将当前文档及其历史记录保存在同一个数据库中,并避免使用多个系统来管理数据历史记录。

About this Task关于此任务

The Document Versioning Pattern works best if your data meets these criteria:如果数据符合以下条件,文档版本控制模式最有效:

  • Documents are updated infrequently.文档更新不频繁。
  • There are few documents that require version tracking.很少有文档需要版本跟踪。
  • Current data and historical data are generally queried separately. In the Document Versioning Pattern, historical data is stored in a separate collection from the current data, so returning both in the same operation can be expensive.当前数据和历史数据通常是分开查询的。在文档版本控制模式中,历史数据与当前数据存储在单独的集合中,因此在同一操作中同时返回这两个数据可能代价高昂。

If the preceding criteria do not fit your use case, consider a different solution or change how you implement the Document Versioning Pattern.如果上述标准不符合用例,请考虑其他解决方案或更改文档版本控制模式的实现方式。

Before you Begin开始之前

In the following example, an insurance company uses the Document Versioning Pattern to track changes to customer policies. Insert the sample document into the currentPolicies and policyRevisions collections:在下面的示例中,一家保险公司使用文档版本控制模式来跟踪客户保单的更改。将示例文档插入到currentPolicies(当前策略)和policyRevisions(策略修订)集合中:

db.currentPolicies.insertOne(
{
policyId: 1,
customerName: "Michelle",
revision: 1,
itemsInsured: [
"golf clubs",
"car"
],
dateSet: new Date()
}
)
db.policyRevisions.insertOne(
{
policyId: 1,
customerName: "Michelle",
revision: 1,
itemsInsured: [
"golf clubs",
"car"
],
dateSet: new Date()
}
)

Steps步骤

With the Document Versioning Pattern, when a policy is updated, the following writes occur:使用文档版本控制模式,当更新策略时,会发生以下写入操作:

  • The policy is updated in the currentPolicies collection. The currentPolicies collection only contains the current data revision of each policyId.该策略在currentPolicies集合中更新。currentPolicies集合仅包含每个policyId的当前数据修订。
  • The original policy is written to the policyRevisions collection to keep a record of policy changes.原始策略会写入policyRevisions集合,以记录策略更改。

For example, if the user Michelle wants to add a watch to her policy, the application runs these operations:例如,如果用户Michelle想要将手表添加到她的策略中,应用程序将运行以下操作:

1

Update the policy in the currentPolicies collection更新当前Policies集合中的策略

db.currentPolicies.updateOne(
{ policyId: 1 },
{
$push: {
itemsInsured: "watch"
},
$inc: {
revision: 1
},
$currentDate: {
dateSet: true
}
}
)

Updated document:更新文件:

{
_id: ObjectId("661e873d1a930b8ea1f75c57"),
policyId: 1,
customerName: 'Michelle',
revision: 2,
itemsInsured: [ 'golf clubs', 'car', 'watch' ],
dateSet: ISODate("2024-04-16T14:12:24.476Z")
}
2

Write the updated policy to the policyRevisions collection将更新的策略写入policyRevisions集合

db.currentPolicies.aggregate( [
{
$match: { policyId: 1 }
},
{
$set: { _id: new ObjectId() }
},
{
$merge: {
into: { db: "test", coll: "policyRevisions" },
on: "_id",
whenNotMatched: "insert"
}
}
] )

After you run the previous aggregation, the policyRevisions collection contains both the original and updated policies:运行之前的聚合后,policyRevisions集合包含原始和更新的策略:

[
{
_id: ObjectId("6626c8f02a98aba8ddec31d1"),
policyId: 1,
customerName: 'Michelle',
revision: 1,
itemsInsured: [ 'golf clubs', 'car' ],
dateSet: ISODate("2024-04-22T20:30:40.809Z")
},
{
_id: ObjectId("6626c92b2a98aba8ddec31d2"),
customerName: 'Michelle',
dateSet: ISODate("2024-04-22T20:31:03.000Z"),
itemsInsured: [ 'golf clubs', 'car', 'watch' ],
policyId: 1,
revision: 2
}
]

Next Steps后续步骤

To view a customer's policy history, you can sort the policyRevisions collection by revision. Consider if the customer Michelle makes another change to her policy and no longer wants to insure her golf clubs.要查看客户的保单历史记录,您可以按修订对policyRevisions集合进行排序。考虑一下客户Michelle是否再次更改了她的保单,不再想为她的高尔夫球杆投保。

1

Update the policy in the currentPolicies collection更新当前Policies集合中的策略

db.currentPolicies.updateOne(
{ policyId: 1 },
{
$pull: {
itemsInsured: "golf clubs"
},
$inc: {
revision: 1
},
$currentDate: {
dateSet: true
}
}
)

Updated document:更新文件:

{
_id: ObjectId("661e873d1a930b8ea1f75c57"),
policyId: 1,
customerName: 'Michelle',
revision: 3,
itemsInsured: [ 'car', 'watch' ],
dateSet: ISODate("2024-04-16T14:13:38.203Z")
}
2

Write the updated policy to the policyRevisions collection将更新的策略写入policyRevisions集合

db.currentPolicies.aggregate( [
{
$match: { policyId: 1 }
},
{
$set: { _id: new ObjectId() }
},
{
$merge: {
into: { db: "test", coll: "policyRevisions" },
on: "_id",
whenNotMatched: "insert"
}
}
] )
3

Return a history of the policy changes返回政策更改的历史记录

db.policyRevisions.find( { policyId: 1 } ).sort( { revision: 1 } )

Output:输出:

[
{
_id: ObjectId("6626c8f02a98aba8ddec31d1"),
policyId: 1,
customerName: 'Michelle',
revision: 1,
itemsInsured: [ 'golf clubs', 'car' ],
dateSet: ISODate("2024-04-22T20:30:40.809Z")
},
{
_id: ObjectId("6626c92b2a98aba8ddec31d2"),
customerName: 'Michelle',
dateSet: ISODate("2024-04-22T20:31:03.000Z"),
itemsInsured: [ 'golf clubs', 'car', 'watch' ],
policyId: 1,
revision: 2
},
{
_id: ObjectId("6626c9832a98aba8ddec31d3"),
customerName: 'Michelle',
dateSet: ISODate("2024-04-22T20:32:43.232Z"),
itemsInsured: [ 'car', 'watch' ],
policyId: 1,
revision: 3
}
]

Learn More了解更多