mongodb文档删除-deleteMany()

1. 环境信息

数据库版本是否集群节点个数库数据大小
mongodb3.6.33120+GB
  1. mongodb中有一库,该库下的某一集合下的文档数据增长快速,2~3周时间增长40GB左右
  2. 数据库增长导致磁盘空间使用增长,而且主机每天备份mongodb,磁盘使用过大
  3. 该集合下文档数据类似日志记录信息,可以删除,故考虑删除文档数据

2. mongodb集合文档数据删除

2.1 remove()

  1. 删除集合文档数据:db.collection.remove()
db.collection.remove(
   <query>,
   {
     justOne: <boolean>,
     writeConcern: <document>,
     collation: <document>
   }
)
  1. 删除后清理磁盘空间:db.repairDatabase(),下面根据不同数据库存储引擎的一些执行条件。
    MMAPv1 :
    repairDatabase需要的可用磁盘空间等于当前数据集的大小再加上2 GB。如果保存dbpath的卷缺少足够的空间,则可以装入单独的卷并将其用于修复。当安装一个单独的卷时, repairDatabase必须从命令行运行repairDatabase ,并使用 --repairpath 开关指定用于存储临时修复文件的文件夹。
    WiredTiger :
    repairDatabase 执行就地操作,不需要额外的磁盘空间。
  2. 不建议使用.remove()删除文档数据,数据量过大可能导致mongodb夯死,上层服务不可用。
  3. mongodb3.2版本后新增了deleteMany()删除动作,该环境版本3.6,后面实战删除动作使用的就是deleteMany()。

2.2 deleteMany()

使用deleteMany()删除文档数据:编辑删除条件,删除对应的数据,当然数据量特别大的情况下,建议根据条件分批次删除文档数据。

db.collection.deleteMany(
   <filter>,
   {
      writeConcern: <document>,
      collation: <document>
   }
)

删除id值的文档信息:
db.getCollection("集合名称").deleteMany({_id : ObjectId("文档实际id值")})
db.getCollection("cc_OperationLog").deleteMany({_id : ObjectId("5e901b653d323ee89b87c238")})

3. mongodb存储引擎

查看当前使用存储引擎:db.serverStatus()在这里插入图片描述
The WiredTiger storage engine maintains lists of empty records in data files as it deletes documents. This space can be reused by WiredTiger, but will not be returned to the operating system unless under very specific circumstances.
WiredTiger存储引擎在删除文档时会维护数据文件中的空记录列表。WiredTiger可以重用此空间,但是除非在非常特殊的情况下,否则不会将其返回给操作系统。

使用deleteMany删除完文档数据后,使用show dbs查看mongodb下数据库并没有释放掉数据,du - csh查看mongodb在主机的数据路径下的大小也没有降低,因为使用了WiredTiger存储引擎,无需释放磁盘空间,存储引擎会重复利用磁盘空间(实际清理完100G左右数据后,在大概1~2天时间内,因为该集合不断在写入数据,存储引擎覆写wt文件,实际释放了磁盘空间,使用show dbs或查看os磁盘空间,发现明显数值降低,释放了空间),如果想要快速释放磁盘空间,在删除完集合下文档数据后,离线其中一个节点,删除该节点主机的数据路径,之后启动,该节点会加入集群去重新同步数据(因为已经删除了库中大量数据,同步会快速完成),之后将其他节点也类似操作,可以快速释放磁盘空间,并且不影响上层服务使用(只在停止primary节点的时候,其他节点重新选举primary时候耗时,导致服务连接不上mongodb)。

4. 删除实战

  1. 下面脚本没有使用perl连接mongodb库的模块,使用mongo shell模式执行命令
  2. 脚本逻辑先判断集合内文档的最新时间戳和最老的时间戳,以一定的时间间隔(1h),循环删除文档数据(循环删除防止单次删除时数据量太大,我们实际环境1h内平均在7w条数据)
  3. 脚本使用请根据实际修改
#!/usr/bin/perl
$export_l=`export LANG=C && export LC_ALL=C`;

print "清理cc_OperationLog文档集合";
print "\n";print "\n";sleep(1);

print "--输入mongo信息,如“mongo xx.xx.xx.xx:27017/cmdb -u user-p passwd”,回车确定!\n";
our $mongodb_info=<STDIN>;		our $mongodb_info=~s/\n//;	

print "\n";print "\n";sleep(1);
our $h36="36";
#获取mongo文档时间信息
our @mongo_time_infos=GetMongodbTime(); 
print "----------$mongo_time_infos[2]----\n";

$date_start=`date`;
$cdi=$mongo_time_infos[2];

#循环删除当前36小时之前数据
for ($cdi;$cdi>=$h36;$cdi=$cdi-1){
	#$ddi=$di+1;
	$delete_mongo=CheckAndDelete($cdi);
}
$date_end=`date`;

print "开始:$date_start结束:$date_end\n";

#获取mongo文档时间信息
sub GetMongodbTime{
	#获取最新_id和时间戳
	$mongoshell_idnow=`$mongodb_info  --eval \"db.getCollection(\\\"cc_OperationLog\\\").find({},{_id:1}).sort({_id:-1}).limit(1)\" `;
	@arr_mongoshell_idnow=split('\n',$mongoshell_idnow);  
	$arr_mongoshell_idnow[-1]=~s/[(|)|{|}|\"]//g;
	$arr_mongoshell_idnow[-1]=~s/(.+)+(ObjectId)+(.+)/$3/g;
	$arr_mongoshell_idnows=$arr_mongoshell_idnow[-1];$arr_mongoshell_idnows=~s/\n|\s+//g;

	$mongoshell_timenow=`$mongodb_info  --eval \"ObjectId('$arr_mongoshell_idnows').getTimestamp().getTime()/1000\" `;
	@arr_mongoshell_timenow=split('\n',$mongoshell_timenow);  
	$arr_mongoshell_timenow[-1]=~s/\n|\s+//g;
	#print "$arr_mongoshell_idnows\n$arr_mongoshell_timenow[-1]\n";

	#获取最早_id和时间戳
	$mongoshell_idold=`$mongodb_info  --eval \"db.getCollection(\\\"cc_OperationLog\\\").find({},{_id:1}).sort({_id:1}).limit(1)\" `;
	@arr_mongoshell_idold=split('\n',$mongoshell_idold);  
	$arr_mongoshell_idold[-1]=~s/[(|)|{|}|\"]//g;
	$arr_mongoshell_idold[-1]=~s/(.+)+(ObjectId)+(.+)/$3/g;
	$arr_mongoshell_idolds=$arr_mongoshell_idold[-1];$arr_mongoshell_idolds=~s/\n|\s+//g;

	$mongoshell_timeold=`$mongodb_info  --eval \"ObjectId('$arr_mongoshell_idolds').getTimestamp().getTime()/1000\" `;
	@arr_mongoshell_timeold=split('\n',$mongoshell_timeold);  
	$arr_mongoshell_timeold[-1]=~s/\n|\s+//g;
	#print "$arr_mongoshell_idolds\n$arr_mongoshell_timeold[-1]\n";

	#时间差,单位小时
	$time_difference=($arr_mongoshell_timenow[-1] - $arr_mongoshell_timeold[-1]) / 3600;
	$time_difference=sprintf "%.0f",$time_difference;
	#print "$time_difference\n";

	print"\n当前时间戳:$arr_mongoshell_timenow[-1],最早文档时间戳:$arr_mongoshell_timeold[-1]\n";
	if ($time_difference <= $h36)
	{
		print "当前文档时间差是$time_difference小时,小于$h36小时,如文档个数太多需删除文档,请手动删除!\n";
		exit 0;
	}
	else {
		print "当前文档时间差是$time_difference小时,大于$h36小时,稍后脚本会循环删除$h36小时之前的文档!\n";
	}

	@mongo_time_info;
	push(@mongo_time_info, "$arr_mongoshell_timenow[-1]", "$arr_mongoshell_timeold[-1]", "$time_difference");
	return (@mongo_time_info);
}


#查询/删除
sub CheckAndDelete{
@db_list = @_;
#$db_list[0],$db_list[1]时间点

$check_mongo=`$mongodb_info  --eval \"db.getCollection(\\\"cc_OperationLog\\\").find({_id:{\\\$lt:new ObjectId( Math.floor(new Date(new Date()-1000*60*60*$db_list[0]).getTime()/1000).toString(16) + \\\"0000000000000000\\\" )}}).count()\" `;
#print "--111---$check_mongo\n";
@arr_check_mongo=split('\n',$check_mongo);  
$arr_check_mongo[-1]=~s/\n|\s+//g;#print "--2222---$arr_check_mongo[-1]\n";

if ( $arr_check_mongo[-1] >= 70000 ) {
    print "该时间段文档为:$arr_check_mongo[-1],超过7w条,是否需要删除,请输入:Y/N\n";
	$delete_confirmation=<STDIN>;		$delete_confirmation=~s/\n//;	

	if ( $delete_confirmation eq "Y" ) {
		$delete_db=`$mongodb_info  --eval \"db.getCollection(\\\"cc_OperationLog\\\").deleteMany({_id:{\\\$lt:new ObjectId( Math.floor(new Date(new Date()-1000*60*60*$db_list[0]).getTime()/1000).toString(16) + \\\"0000000000000000\\\" )}})\"`;
		print "已删除$db_list[0]小时之前文档数据,删除$arr_check_mongo[-1]条\n";
	}
	elsif( $delete_confirmation eq "N") {
		print "$db_list[0]小时之前文档数据$arr_check_mongo[-1]条,数据量大,暂时不删除\n";
	}
}
elsif ( $arr_check_mongo[-1]>0 and $arr_check_mongo[-1]<50000) {
	$delete_db=`$mongodb_info  --eval \"db.getCollection(\\\"cc_OperationLog\\\").deleteMany({_id:{\\\$lt:new ObjectId( Math.floor(new Date(new Date()-1000*60*60*$db_list[0]).getTime()/1000).toString(16) + \\\"0000000000000000\\\" )}})\"`;
	print "已删除$db_list[0]小时之前文档数据,删除$arr_check_mongo[-1]条\n";
}
elsif ($arr_check_mongo[-1] eq 0 ) {
	print "$db_list[0]小时之前文档数据,存在$arr_check_mongo[-1]条\n";
}
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值