pymong 批量删除mongogridfs 文件

pymong 删除 mongogridfs 文件

一. 背景:

Gridfs 图片服务器存储

GridFS是MongoDB中存储和查询超过BSON文件大小限制(16M)的规范,不像BSON文件那样在一个单独的文档中存储文件,GridFS将文件分成多个块,每个块作为一个单独的文档。默认情况下,每个GridFS块是255kB,意味着除了最后一个块之外(根据剩余的文件大小),文档被分成多个255kB大小的块存储。

GridFS使用两个集合保存数据,一个集合存储文件块(fs.chunks),另外一个存储文件元数据(fs.files)。fs.chunks中每个chunk块大小为256KB,mongo的副本集和分片架构为GridFS提供了高效的读写扩展能力和高可用能力,在图片,视频,等大文件的存储方面具有较高的性能. [小文件,小文当(< 16M)保存在Bson二进制,大文件保存在gridfs].

在这里插入图片描述

公司项目图片服务器采用mongo副本集的gridfs来实现,上面存储jpg图片,mp3 音频,视频和sitemap文件. 近期图片服务器有一批一批的违规图片需要集中清理. 批量清理文件.

二. 当前问题:

mongofs gridfs 操作方案:

mongo文件系统gridfs 使用过程中,mongo提供了命令 mongofiles进行管理。

[root@bj-test-wlj-2-132 twj]# mongofiles --help
Browse and modify a GridFS filesystem.

usage: mongofiles [options] command [gridfs filename]
command:
  one of (list|search|put|get)
  list - list all files.  'gridfs filename' is an optional prefix 
         which listed filenames must begin with.
  search - search all files. 'gridfs filename' is a substring 
           which listed filenames must contain.
  put - add a file with filename 'gridfs filename'
  get - get a file with filename 'gridfs filename'
  delete - delete all files with filename 'gridfs filename'
options:
  --help                                produce help message
  -v [ --verbose ]                      be more verbose (include multiple times
                                        for more verbosity e.g. -vvvvv)
  --version                             print the program's version and exit
  -h [ --host ] arg                     mongo host to connect to ( <set 
                                        name>/s1,s2 for sets)
  --port arg                            server port. Can also use --host 
                                        hostname:port
  --ipv6                                enable IPv6 support (disabled by 
                                        default)
  -u [ --username ] arg                 username
  -p [ --password ] arg                 password
  --authenticationDatabase arg          user source (defaults to dbname)
  --authenticationMechanism arg (=MONGODB-CR)
                                        authentication mechanism
  --dbpath arg                          directly access mongod database files 
                                        in the given path, instead of 
                                        connecting to a mongod  server - needs 
                                        to lock the data directory, so cannot 
                                        be used if a mongod is currently 
                                        accessing the same path
  --directoryperdb                      each db is in a separate directly 
                                        (relevant only if dbpath specified)
  --journal                             enable journaling (relevant only if 
                                        dbpath specified)
  -d [ --db ] arg                       database to use
  -c [ --collection ] arg               collection to use (some commands)
  -l [ --local ] arg                    local filename for put|get (default is 
                                        to use the same name as 'gridfs 
                                        filename')
  -t [ --type ] arg                     MIME type for put (default is to omit)
  -r [ --replace ]                      Remove other files with same name after
                                        PUT

其中,删除文件操作:

mongofiles delete 文件名 --port 端口 --db 库名

mongofiles delete xxx.jpg --port 30000 --db pics
批量删除文件案例:

由于 需要删除的文件巨大,一批可能有5 ~ 6 十万,使用mongofiles 命令每次删除文件,都需要建立一次tcp连接. 于是临时把url放到文件中,然后差分文件,循环执行+sleep 缓解tcp端口占满:

for file in `ls`;do  for i in `cat 31aa*`;do echo " mongofiles delete $i --port 30000 --db pics" >> 2021-8-31.log && mongofiles delete $i --port 30000 --db pic  sleep 0.1 ;done ; echo sleep 60 ;sleep 120 ;done
风险点:
  • 使用mongofiles 命令可以临时删除少量数据,且操作较慢
  • 存在tcpdump数占满,mongo 连接数跑满的风险
  • 在使用过程中发现,批量删除的文件量 大于 10000 就会出现删除失败的情况. mongofiles 提示操作成功,但文件依然存在

三. 解决方案:

开发临时解决:

由于shell命令批量处理异常文件,发现很多文件出现了操作失败的情况, 临时找开发进行处理。经了解,开发采用java语言使用mongo的驱动模块封装的方法remove,直接删除文件。

import com.mongodb.DB;
import com.mongodb.DBObject;
import com.mongodb.Mongo;
import com.mongodb.gridfs.GridFS;
import com.mongodb.gridfs.GridFSDBFile;



public class MyGridFsTest {
	private String host = "127.0.0.1";
	private int port = 27017;
	private String dbName = "demogridfs";



	@Test
	public void testFindFile() throws IOException{
		Mongo connection = new Mongo(host, port);
		DB db = connection.getDB(dbName);
		GridFS gridFs = new GridFS(db);

		DBObject query = new BasicDBObject("filename", fileName);
		gridFs.remove(query);

java 的Mongo驱动二次封装直接删除文件,而且采用mongo线程池,不过多的占用Mongo连接数等资源。

python pymongo 解决方案:

官方地址
在这里插入图片描述

(pymongo) [root@bj-redis-slave02-10-8-2-245 history]# python delete-pic.py > 2021-8.log &

(pymongo) [root@bj-redis-slave02-10-8-2-245 history]# tail -f 2021-8.log 

四. 附: 代码:

#!/usr/bin/python
# -*- encoding: utf-8 -*-
import pymongo
import json
import os
from pymongo import MongoClient
from gridfs import GridFS
class GFS(object):
    def __init__(self, file_db,file_table):
        self.file_db = file_db
        self.file_table = file_table
 
    def createDB(self): #连接数据库,并创建文件数据库与数据表
        client = MongoClient('10.8.2.237',30000)
        db = client[self.file_db]
        file_table = db[self.file_table]
        return (db,file_table)
 
    def insertFile(self,db,filePath,query): #将文件存入数据表
        fs = GridFS(db,self.file_table)
        if fs.exists(query):
            print('已经存在该文件')
        else:
            with open(filePath,'rb') as fileObj:
                data = fileObj.read()
                ObjectId = fs.put(data,filename = filePath.split('/')[-1])
                print(ObjectId)
                fileObj.close()
            return ObjectId
 
    def getID(self,db,query,pic): #通过文件属性获取文件ID,ID为文件删除、文件读取做准备
        try:
            fs=GridFS(db, self.file_table)
            ObjectId=fs.find_one(query)._id
            msg=pic,'ObjectId',ObjectId
            print (msg)
            return ObjectId
        except AttributeError as e: #AttributeError为错误类型,此种错误的类型赋值给变量e;当try与except之间的语句触发
                                    # AttributeError错误时程序不会异常退出而是执行except AttributeError下面的内容
            print("AttributeError错误,图片不存在:",e)
            
    def remove(self,db,id): #文件数据库中数据的删除
        fs = GridFS(db, self.file_table)        
        fs.delete(id) #只能是id
        del_msg= id,'正在删除!!!'
        print (del_msg)
 
    def getFile(self,db,id): #获取文件属性,并读出二进制数据至内存
        fs = GridFS(db, self.file_table)
        gf=fs.get(id)
        bdata=gf.read() #二进制数据
        attri={} #文件属性信息
        attri['chunk_size']=gf.chunk_size
        attri['length']=gf.length
        attri["upload_date"] = gf.upload_date
        attri["filename"] = gf.filename
        attri['md5']=gf.md5
        print(attri)
        return (bdata, attri)
    def Writ_log(self,File,msg):
        f=open(File,'a')
        f.write(msg)
        f.close()
 
    def listFile(self,db): #列出所有文件名
        fs = GridFS(db, self.file_table)
        gf = fs.list()
 
    def findFile(self,db,file_table): #列出所有文件二进制数据
        fs = GridFS(db, table)
        for file in fs.find():
            bdata=file.read()
 
    def write_2_disk(self,bdata, attri): #将二进制数据存入磁盘
        name = "get_"+attri['filename']
        if name:
            output = open(name, 'wb')
        output.write(bdata)
        output.close()
        print("fetch image ok!")
 
if __name__=='__main__':
    gfs=GFS('pics','fs')
    (file_db,fileTable) = gfs.createDB() #创建数据库与数据表
    dir_list = os.listdir('2021-8')
    print (dir_list)
    for filePath in dir_list:
        filePath='2021-8/'+filePath
        lines = open(filePath,'r').readlines()
        for file in lines:
            pic =file.splitlines()[0]
            query = '{"filename": "%s"}' %(pic)
            query = json.loads(query)
            id=gfs.getID(file_db,query,pic)
            gfs.remove(file_db,id) #删除数据库中文件


    #filePath = '10.txt' #插入的文件
    #query = {'filename': '745082993188.jpg'}
    #id=gfs.getID(file_db,query,pic)
    #gfs.remove(file_db,id) #删除数据库中文件
    
    #id=gfs.insertFile(file_db,filePath,query) #插入文件 
    #(bdata,attri)=gfs.getFile(file_db,id) #查询并获取文件信息至内存    
    #gfs.write_2_disk(bdata,attri) #写入磁盘
    #gfs.remove(file_db,id) #删除数据库中文件
参考:

pymongo 对mongo nosql的操作 教程较多,多gridfs 文件系统的上传下载介绍较多。但对gridfs delete操作 介绍较少。核心重要的操作是,先获取文件的文件id,然后通过remove方法移除文件id。(remove 文件方法只接受文件id)

官方: https://pymongo.readthedocs.io/en/stable/tutorial.html

gridfs delete 官方: https://pymongo.readthedocs.io/en/stable/api/gridfs/index.html?highlight=delete#gridfs.GridFS.delete

https://blog.csdn.net/qq_30852577/article/details/84645693

https://blog.csdn.net/weiyuanke/article/details/7717476

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值