使用 MongoDB 處理重復數(shù)據(jù)及批量生成數(shù)據(jù)的實踐
在實際開發(fā)中,處理大量數(shù)據(jù)時,可能會遇到重復數(shù)據(jù)、批量插入等需求。以下是一個 MongoDB 實戰(zhàn)案例,包括批量生成數(shù)據(jù)、刪除重復數(shù)據(jù)以及數(shù)據(jù)去重后的索引優(yōu)化。
1、批量插入數(shù)據(jù)
場景
我們需要為某個設(shè)備在每月生成一條記錄,涉及以下條件:
- 設(shè)備編號在一定范圍內(nèi)。
- 每月固定日期生成時間戳。
- 特定字段的值在一個范圍內(nèi)隨機生成。
解決方案
利用 MongoDB 的批量插入功能,通過 JavaScript 腳本批量生成數(shù)據(jù):
插入腳本
// 定義設(shè)備編號范圍
var startDevice = 1001;
var endDevice = 1120;
// 定義每月時間戳(示例時間)
var timestamps = [
NumberLong(1727731200000), // 2024-10-01 0:00:00
NumberLong(1730323200000), // 2024-11-01 0:00:00
NumberLong(1733001600000) // 2024-12-01 0:00:00
];
// 批量插入數(shù)據(jù)
for (var tsIdx = 0; tsIdx < timestamps.length; tsIdx++) {
var calcBeginDate = timestamps[tsIdx];
for (var deviceCode = startDevice; deviceCode <= endDevice; deviceCode++) {
var randomValue = (Math.random() * (0.9999 - 0.9800) + 0.9800).toFixed(4); // 隨機值生成
// 構(gòu)建文檔
var document = {
"deviceCode": "D" + deviceCode, // 替換設(shè)備編號
"type": "months",
"calcTime": calcTime,
"type0": NumberLong(0),
"type1": NumberLong(0),
"type2": NumberLong(0),
"type3": NumberLong(0),
"type4": NumberLong(0),
"flag": "1",
"ta": parseFloat(randomValue), // 隨機值
"updateTime": NumberLong(Date.now()),
"createTime": NumberLong(Date.now()),
"_class": "com.example.data.entity.Entity"
};
// 插入到集合
db.device_data.insert(document);
}
}
注意事項
1.執(zhí)行腳本前,確保集合已存在,避免插入失敗。
2.生成的隨機數(shù)范圍和設(shè)備編號范圍可根據(jù)實際需求調(diào)整。
2、刪除重復數(shù)據(jù)
場景
由于多次執(zhí)行插入腳本,可能導致集合中存在重復數(shù)據(jù)。重復的定義是:
同一設(shè)備在同一個時間點(如每月初)的記錄有多條。
解決方案
通過 MongoDB 的聚合和刪除操作,刪除重復數(shù)據(jù),僅保留每組中的一條。
刪除重復數(shù)據(jù)的腳本
// 刪除重復數(shù)據(jù),保留每組唯一數(shù)據(jù)
db.device_data.aggregate([
{
$group: {
_id: { deviceCode: "$deviceCode", calcBeginDate: "$calcBeginDate" },
duplicateIds: { $push: "$_id" } // 收集所有重復的 _id
}
},
{
$project: {
_id: 0,
keepId: { $arrayElemAt: ["$duplicateIds", 0] }, // 保留第一個 _id
deleteIds: { $slice: ["$duplicateIds", 1, { $size: "$duplicateIds" }] } // 需要刪除的 _id
}
}
]).forEach(function(doc) {
// 刪除所有多余的 _id
if (doc.deleteIds.length > 0) {
db.device_data.remove({ _id: { $in: doc.deleteIds } });
}
});
腳本說明
1.分組:使用$group按deviceCode和calcBeginDate分組,將重復的_id收集到duplicateIds。
2.數(shù)據(jù)分離:保留第一條記錄的_id(keepId),將其余的標記為需要刪除的記錄(deleteIds)。
3.刪除操作:遍歷結(jié)果,對deleteIds 中的文檔執(zhí)行刪除。
3、數(shù)據(jù)去重后的索引優(yōu)化
場景
在清理數(shù)據(jù)后,為了避免重復數(shù)據(jù)再次出現(xiàn),可以為集合創(chuàng)建唯一索引。
解決方案
為deviceCode 和calcBeginDate 創(chuàng)建復合唯一索引,確保每個設(shè)備每月只有一條記錄。
索引創(chuàng)建腳本
db.device_data.createIndex(
{ deviceCode: 1, calcBeginDate: 1 },
{ unique: true }
);
注意事項
1.在創(chuàng)建唯一索引前,必須確保數(shù)據(jù)中沒有重復記錄,否則索引創(chuàng)建會失敗。
2.索引創(chuàng)建成功后,重復插入相同鍵值對的操作將會報錯。
總結(jié)
通過以上方法,可以實現(xiàn)以下目標:
1.批量生成數(shù)據(jù):高效插入多條滿足特定條件的數(shù)據(jù)。
2.刪除重復數(shù)據(jù):清理因腳本多次執(zhí)行或其他原因?qū)е碌闹貜陀涗洝?/span>
3.防止重復數(shù)據(jù)再次出現(xiàn):通過創(chuàng)建唯一索引,從數(shù)據(jù)層面杜絕重復。
在實際操作中,建議先備份數(shù)據(jù),確保腳本執(zhí)行安全可靠。同時,可以將這些腳本封裝為工具類或定期任務(wù),進一步提升效率。