使用 MongoDB 處理重復(fù)數(shù)據(jù)及批量生成數(shù)據(jù)的實(shí)踐
在實(shí)際開發(fā)中,處理大量數(shù)據(jù)時(shí),可能會遇到重復(fù)數(shù)據(jù)、批量插入等需求。以下是一個(gè) MongoDB 實(shí)戰(zhàn)案例,包括批量生成數(shù)據(jù)、刪除重復(fù)數(shù)據(jù)以及數(shù)據(jù)去重后的索引優(yōu)化。

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























