Docs 菜单

存档模式

如果需要存储多年前的历史数据,将最旧的数据与最新的数据存储在同一个数据库中,可能会对性能影响,尤其是在不需要经常访问旧数据的情况下。相反,您可以设计模式以存档旧数据并将该数据移动到单独的存储位置。

有多种存储存档数据的选项。示例,您可以:

  • 将数据移动到外部文件存储,例如Amazon S3。

  • 将数据移至成本更低的独立集群。

  • 将数据移至同一集群上的单独集合。

在大多数情况下,就费用和性能而言,将数据移动到外部文件存储是最佳选择。如果您的使用案例无法实现外部文件存储,请考虑将数据移至单独的集群或集合。

在实现数据存档设计模式之前,查看以下最佳实践:

  • 您的存档数据应使用 嵌入式数据模型,而不是引用其他集合。查询存档数据时,数据的所有相关组成部分必须来自同一时间。嵌入数据可确保查询同时返回相关数据。

  • 文档的年龄应包含在单个字段中。

  • 如果您有永不过期或永不移动到存档的文档,请将文档期限设立为 keep forever 或类似的字符串,以指示该文档必须保留在活动集合中。

  • MongoDB Atlas提供 Online 存档,可将不常访问的数据从Atlas 集群移动到云对象存储上MongoDB托管的只读联合数据库实例。

在此示例中,一家电子商务存储希望存档五年多前发生的销售数据。初始数据集包含所有销售,较旧销售的文档将移动到单独的集合。

1
db.sales.insertMany( [
{
customer_name: "Hiroshi Tanaka",
products: [
{
product_id: "P1001",
name: "Wireless Headphones",
quantity: 1,
price: 59.99
},
{
product_id: "P1002",
name: "Phone Charger",
quantity: 2,
price: 14.99
}
],
total_amount: 89.97,
date: ISODate("2025-01-30T10:15:00Z")
},
{
customer_name: "Aisha Khan",
products: [
{
product_id: "P1003",
name: "Laptop",
quantity: 1,
price: 899.99
}
],
total_amount: 899.99,
date: ISODate("2018-11-20T15:45:00Z") // Over 5 years ago
},
{
customer_name: "Fatima Al-Farsi",
products: [
{
product_id: "P1006",
name: "Gaming Mouse",
quantity: 1,
price: 49.99
},
{
product_id: "P1007",
name: "Mechanical Keyboard",
quantity: 1,
price: 129.99
}
],
total_amount: 179.98,
date: ISODate("2017-06-15T12:00:00Z") // Over 5 years ago
},
{
customer_name: "Nguyen Minh",
products: [
{
product_id: "P1008",
name: "Bluetooth Speaker",
quantity: 2,
price: 39.99
}
],
total_amount: 79.98,
date: ISODate("2025-01-26T09:20:00Z")
}
] )
2

注意

以下脚本使用MongoDB Shell语法。要查看驾驶员的聚合和查询语法,请参阅驾驶员文档。

// Set a variable to five years before the time that the script runs
const fiveYearsAgo = new Date();
fiveYearsAgo.setFullYear(fiveYearsAgo.getFullYear() - 5);
// Write old sales to the 'archived_sales' collection
const writeOldSalesPipeline = [
{
$match: {
date: { $lt: fiveYearsAgo }
}
},
{
$merge: {
into: {
db: "test",
coll: "archived_sales",
},
on: "_id"
}
}
]
db.sales.aggregate(writeOldSalesPipeline)
// Delete old sales from the active 'sales' collection
try {
db.sales.deleteMany(
{ date : { $lt: fiveYearsAgo } }
);
} catch (e) {
print (e);
}

运行脚本后,sales集合将不再包含五年前的销售额。

db.sales.find()

输出:

[
{
_id: ObjectId('679ced18fa29d32ca7d1abab'),
customer_name: 'Hiroshi Tanaka',
products: [
{
product_id: 'P1001',
name: 'Wireless Headphones',
quantity: 1,
price: 59.99
},
{
product_id: 'P1002',
name: 'Phone Charger',
quantity: 2,
price: 14.99
}
],
total_amount: 89.97,
date: ISODate('2025-01-30T10:15:00.000Z')
},
{
_id: ObjectId('679ced18fa29d32ca7d1abae'),
customer_name: 'Nguyen Minh',
products: [
{
product_id: 'P1008',
name: 'Bluetooth Speaker',
quantity: 2,
price: 39.99
}
],
total_amount: 79.98,
date: ISODate('2025-01-26T09:20:00.000Z')
}
]

旧销售现在存在于 archived_sales集合中。

db.archived_sales.find()

输出:

[
{
_id: ObjectId('679ced18fa29d32ca7d1abac'),
customer_name: 'Aisha Khan',
products: [
{
product_id: 'P1003',
name: 'Laptop',
quantity: 1,
price: 899.99
}
],
total_amount: 899.99,
date: ISODate('2018-11-20T15:45:00.000Z')
},
{
_id: ObjectId('679ced18fa29d32ca7d1abad'),
customer_name: 'Fatima Al-Farsi',
products: [
{
product_id: 'P1006',
name: 'Gaming Mouse',
quantity: 1,
price: 49.99
},
{
product_id: 'P1007',
name: 'Mechanical Keyboard',
quantity: 1,
price: 129.99
}
],
total_amount: 179.98,
date: ISODate('2017-06-15T12:00:00.000Z')
}
]