DB/MongoDB

mongodb - GridFS save/read file 예제

linuxism 2013. 6. 10. 14:22


참조 - http://linuxism.tistory.com/1405




MongoDB GridFSTop

IntroductionTop

MongoDB 안에 Large Objects 를 저장할 수 있는 파일시스템 입니다. 간단하게 파일을 저장하여 사용할 수 있고, MongoDB가 설치되어 있으면 자매품격으로 따라오는 녀석입니다. 저장방식은 1개의 파일당 MAX 2GB 사이즈까지 저장가능하며, 256k chunk 단위로 나누어져 저장합니다. 이는 chunks collections 에 나누어진 document 으로 저장됩니다. 이와 meta, filename, content type, 다른 옵션들은 files collection 에 저장됩니다. 즉 files collection 과 chunks collections 은 1:n 관계를 가진다.

SpecTop

GridFS 는 데이타를 저장하기 위해 2개의 collection 구성됩니다.

  • files : metadata 포함
  • chunks : binary chunks (BSON)

GridFS는 하나의 데이타베이스 안에서 네임스페이스를 가질 수 있습니다. 아무것도 지정하지 않은면 기본은 fs 이며, fs.filesfs.chunks Collection이 기본으로 생성됩니다.

2개의 collection 구성Top

filesTop

files의 document 구조를 알아보겠습니다.

  • {
  • "_id" : <unspecified>, // unique ID for this file
  • "length" : data_number, // size of the file in bytes
  • "chunkSize" : data_number, // size of each of the chunks. Default is 256k
  • "uploadDate" : data_date, // date when object first stored
  • "md5" : data_string // result of running the "filemd5" command on this file's chunks
  • }

위 내용은 기본적으로 생성되는 필드이며, 아래와 같이 임의로 지정한 여러필드를 추가할 수 있습니다.

  • {
  • "filename" : data_string, // human name for the file
  • "contentType" : data_string, // valid mime type for the object
  • "aliases" : data_array of data_string, // optional array of alias strings
  • "metadata" : data_object, // anything the user wants to store
  • }

파일 1개가 저장되면, files collection 에는 1개의 row가 입력됩니다.

chunksTop

files collection 과 1:n 으로 관계지어지는 collection 입니다.

  • {
  • "_id" : <unspecified>, // object id of the chunk in the _chunks collection
  • "files_id" : <unspecified>, // 일명 files.id FK 라고 생각하면 됩니다.
  • "n" : chunk_number, // 256k 단위 chunk의 순번입니다. (예) 1,2,3
  • "data" : data_binary, // BSON binary 형태의 데이타입니다.
  • }

files.id와 chunks.filesid 는 FK 형식으로 이어지는 구조입니다.

사용용도Top

제가 사용한 경우는 PostgreSQL 의 각종 로그정보를 Report (html)으로 자세하게 받아볼 수 있는 pgfouine을 사용하는 과정에서 이 데이타를 API 형식으로 확인하는 프로젝트에서 이용되었습니다.

API형식은 http://host/{hostname}/{date} 으로 되어 있어서, 수천대의 서버의 자세한 로그정보를 손쉽게 꺼내어 확인할 수 있었습니다.

Utility mongofilesTop

MongoDB 설치경로의 bin 디렉토리에 mongofiles 라는 명령어가 있습니다. 이것은 GridFS 에 간단하게 저장 및 삭제, 검색, 목록 등 많은 명령을 할 수 있는 도구입니다.

helpTop

  • $ mongofiles -h
  • ERROR: required parameter is missing in 'host'
  • 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
  • --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 if dbpath specified, each db is in a separate
  • directory
  • --journal enable journaling
  • -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

TESTTop

  • // 파일을 생성합니다.
  • $ echo "Hello World" > testfile.txt
  • // testfile.txt를 GridFS에 입력합니다.
  • [root@nodejs:~]# mongofiles put testfile.txt
  • connected to: 127.0.0.1
  • added file: { _id: ObjectId('501a6bba8714e1003494b283'), filename: "testfile.txt", chunkSize: 262144, uploadDate: new Date(1343908794415), md5: "e59ff97941044f85df5297e1c302d260", length: 12 }
  • done!
  • // GridFS에 저장되어 있는 파일 목록을 확인합니다.
  • $ mongofiles list
  • connected to: 127.0.0.1
  • testfile.txt 12
  • // 로컬에 저장되어 있는 testfile.txt 를 삭제합니다.
  • $ rm testfile.txt
  • rm: remove 일반 파일 `testfile.txt'? y
  • // 다시 해당 파일을 GridFS 으로부터 다운로드 하여 복구합니다.
  • [root@nodejs:~]# mongofiles get testfile.txt
  • connected to: 127.0.0.1
  • done write to: testfile.txt
  • // 다운로드된 파일을 확인합니다.
  • [root@nodejs:~]# cat testfile.txt
  • Hello World

Collection 확인Top

위의 TEST 과정을 거치면 자동으로 fs.files, fs.chunks collection이 생성됩니다.

  • $ mongo
  • MongoDB shell version: 2.0.2
  • connecting to: test
  • > use test
  • switched to db test
  • > show collections
  • fs.chunks // 확인!
  • fs.files // 확인!
  • system.indexes

그럼 collections 의 데이타를 확인해보겠습니다.

  • # 이건가?
  • > fs.files.find()
  • Thu Aug 2 21:11:46 ReferenceError: fs is not defined (shell):1
  • # 역시 에러네요. 오랜만에 mongodb를 ㅋㅋ 다시한번
  • # testfile.txt의 정보를 확인할 수 있습니다.
  • > db.fs.files.find()
  • { "_id" : ObjectId("501a6bba8714e1003494b283"), "filename" : "testfile.txt", "chunkSize" : 262144, "uploadDate" : ISODate("2012-08-02T11:59:54.415Z"), "md5" : "e59ff97941044f85df5297e1c302d260", "length" : 12 }
  • # n이 0부터 시작되고, data는 바이너리형태인것을 확인합니다.
  • # 그리고, files_id 는 ObjectId 형식으로 동일한 내용인것을 알 수 있습니다.
  • > db.fs.chunks.find()
  • { "_id" : ObjectId("501a6bba7e0a7ee0226fb956"), "files_id" : ObjectId("501a6bba8714e1003494b283"), "n" : 0, "data" : BinData(0,"SGVsbG8gV29ybGQK") }

추가로 Python 에서 사용했던 소스Top

pymongo installationTop

python에서는 pymongo 를 추천합니다.

  • $ easy_install pymongo
  • Searching for pymongo
  • Reading http://cheeseshop.python.org/pypi/pymongo/
  • Reading http://github.com/mongodb/mongo-python-driver
  • Reading http://cheeseshop.python.org/pypi/pymongo/2.2.1
  • Best match: pymongo 2.2.1
  • Downloading http://pypi.python.org/packages/source/p/pymongo/pymongo-2.2.1.tar.gz#md5=b9e9f844208971f42862d5a205cab1c7
  • Processing pymongo-2.2.1.tar.gz
  • Running pymongo-2.2.1/setup.py -q bdist_egg --dist-dir /tmp/easy_install-vTfsvW/pymongo-2.2.1/egg-dist-tmp-uib8Bs
  • zip_safe flag not set; analyzing archive contents...
  • Adding pymongo 2.2.1 to easy-install.pth file
  • Installed /usr/lib/python2.4/site-packages/pymongo-2.2.1-py2.4-linux-x86_64.egg
  • Processing dependencies for pymongo

대략 이런 클래스Top

pgfouine 작업할 때 작성한 클래스입니다. 참고하세요.

  • !/usr/bin/env python
  • # -*- coding: utf-8 -*-
  • '''
  • * MongoGridFS Wrapper
  • *
  • * @author nanhapark
  • '''
  • # pymongo
  • from pymongo.connection import Connection
  • from pymongo.objectid import ObjectId
  • from gridfs import GridFS
  • # util
  • import types
  • class MongoGridFS:
  • def __init__(self): pass
  • def connect(self, host, port):
  • if isinstance(port, types.StringType) == True:
  • port = int(port)
  • self.instanceConnection = Connection(host, port)
  • def setDB(self, dbname):
  • self.db = self.instanceConnection[dbname]
  • def setGridFS(self, prefix = 'fs'):
  • self.fs = GridFS(self.db, prefix)
  • def put(self, data, **kwargs):
  • self.fs.put(data, **kwargs)
  • def get(self, filename):
  • out = self.fs.get_last_version(filename)
  • return out.read()
  • def main():
  • # 객체생성
  • o = MongoGridFS()
  • # 접속
  • o.connect('localhost', 27017)
  • # db connect
  • o.setDB('test')
  • # GridFS 객체 생성
  • o.setGridFS()
  • # hello.txt 파일등록
  • o.put('hello.txt', filename="hello.txt")
  • # 가져오기
  • ret = o.get('hello.txt')
  • print ret
  • if __name__ == '__main__':
  • main()

결론Top

pgfouine 프로젝트시에 어떻게 하면 html을 쉽게 저장 / 분산할 수 있을까 생각하다가, Mongodb GridFS를 알게 되었는데, 거창한 FileSystem 보다는 훨씬 심플하고 장난감(?) 같은 느낌이랄까요? 그럼 이만 감사합니다. KIN플하세요. ~~~




출처 - http://nodeqa.com/extend_ref/2#toc-top