MongoDB
 sql >> डेटाबेस >  >> NoSQL >> MongoDB

उल्का:क्लाइंट से मोंगो संग्रह बनाम फाइल सिस्टम बनाम ग्रिडएफएस में फाइल अपलोड करना

आप किसी और पैकेज या किसी तीसरे पक्ष का उपयोग किए बिना उल्का के साथ फ़ाइल अपलोडिंग प्राप्त कर सकते हैं

विकल्प 1:DDP, फ़ाइल को मोंगो संग्रह में सहेजना

/*** client.js ***/

// asign a change event into input tag
'change input' : function(event,template){ 
    var file = event.target.files[0]; //assuming 1 file only
    if (!file) return;

    var reader = new FileReader(); //create a reader according to HTML5 File API

    reader.onload = function(event){          
      var buffer = new Uint8Array(reader.result) // convert to binary
      Meteor.call('saveFile', buffer);
    }

    reader.readAsArrayBuffer(file); //read the file as arraybuffer
}

/*** server.js ***/ 

Files = new Mongo.Collection('files');

Meteor.methods({
    'saveFile': function(buffer){
        Files.insert({data:buffer})         
    }   
});

स्पष्टीकरण

सबसे पहले, फ़ाइल को HTML5 फ़ाइल API का उपयोग करके इनपुट से लिया जाता है। नए FileReader का उपयोग करके एक रीडर बनाया जाता है। फ़ाइल को readAsArrayBuffer के रूप में पढ़ा जाता है। यह सरणीबफर, यदि आप कंसोल.लॉग करते हैं, तो {} लौटाता है और डीडीपी इसे वायर पर नहीं भेज सकता है, इसलिए इसे Uint8Array में बदलना होगा।

जब आप इसे Meteor.call में डालते हैं, Meteor स्वचालित रूप से EJSON.stringify(Uint8Array) चलाता है और इसे DDP के साथ भेजता है। आप क्रोम कंसोल वेबसोकेट ट्रैफ़िक में डेटा की जांच कर सकते हैं, आपको बेस 64 जैसा एक स्ट्रिंग दिखाई देगा

सर्वर साइड पर, उल्का EJSON.parse() को कॉल करता है और इसे वापस बफर में बदल देता है

पेशेवरों

  1. सरल, कोई हैकी तरीका नहीं, कोई अतिरिक्त पैकेज नहीं
  2. स्टिक टू द डेटा ऑन द वायर सिद्धांत

विपक्ष

  1. अधिक बैंडविड्थ:परिणामी बेस64 स्ट्रिंग मूल फ़ाइल से ~ 33% बड़ी है
  2. फ़ाइल आकार सीमा:बड़ी फ़ाइलें नहीं भेज सकते (सीमा ~ 16 एमबी?)
  3. कोई कैशिंग नहीं
  4. अभी तक कोई gzip या संपीड़न नहीं है
  5. यदि आप फ़ाइलें प्रकाशित करते हैं तो बहुत सारी मेमोरी लें

विकल्प 2:XHR, क्लाइंट से फाइल सिस्टम पर पोस्ट करें

/*** client.js ***/

// asign a change event into input tag
'change input' : function(event,template){ 
    var file = event.target.files[0]; 
    if (!file) return;      

    var xhr = new XMLHttpRequest(); 
    xhr.open('POST', '/uploadSomeWhere', true);
    xhr.onload = function(event){...}

    xhr.send(file); 
}

/*** server.js ***/ 

var fs = Npm.require('fs');

//using interal webapp or iron:router
WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
    //var start = Date.now()        
    var file = fs.createWriteStream('/path/to/dir/filename'); 

    file.on('error',function(error){...});
    file.on('finish',function(){
        res.writeHead(...) 
        res.end(); //end the respone 
        //console.log('Finish uploading, time taken: ' + Date.now() - start);
    });

    req.pipe(file); //pipe the request to the file
});

स्पष्टीकरण

क्लाइंट में फ़ाइल को पकड़ लिया जाता है, एक XHR ऑब्जेक्ट बनाया जाता है और फ़ाइल को 'POST' के माध्यम से सर्वर पर भेजा जाता है।

सर्वर पर, डेटा को एक अंतर्निहित फ़ाइल सिस्टम में पाइप किया जाता है। आप अतिरिक्त रूप से फ़ाइल नाम निर्धारित कर सकते हैं, सफाई कर सकते हैं या जांच सकते हैं कि यह पहले से मौजूद है या नहीं, आदि।

पेशेवरों

  1. एक्सएचआर 2 का लाभ उठाते हुए ताकि आप ऐरेबफ़र भेज सकें, विकल्प 1 की तुलना में किसी नए फ़ाइल रीडर () की आवश्यकता नहीं है
  2. बेस64 स्ट्रिंग की तुलना में ऐरेबफ़र कम भारी है
  3. कोई आकार सीमा नहीं, मैंने बिना किसी समस्या के स्थानीयहोस्ट में ~ 200 एमबी फ़ाइल भेजी
  4. फ़ाइल सिस्टम mongodb से तेज़ है (इसमें से अधिक बाद में नीचे बेंचमार्किंग में)
  5. संग्रहणीय और gzip

विपक्ष

  1. XHR 2 पुराने ब्राउज़र में उपलब्ध नहीं है, उदा. IE10 के नीचे, लेकिन निश्चित रूप से आप एक पारंपरिक पोस्ट को लागू कर सकते हैं (अगर मैं गलत हूं तो मुझे बताएं)।
  2. /path/to/dir/ उल्का के बाहर होना चाहिए, अन्यथा /public में फ़ाइल लिखने से पुनः लोड होता है

विकल्प 3:XHR, GridFS में सेव करें

/*** client.js ***/

//same as option 2


/*** version A: server.js ***/  

var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = MongoInternals.NpmModule.GridStore;

WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
    //var start = Date.now()        
    var file = new GridStore(db,'filename','w');

    file.open(function(error,gs){
        file.stream(true); //true will close the file automatically once piping finishes

        file.on('error',function(e){...});
        file.on('end',function(){
            res.end(); //send end respone
            //console.log('Finish uploading, time taken: ' + Date.now() - start);
        });

        req.pipe(file);
    });     
});

/*** version B: server.js ***/  

var db = MongoInternals.defaultRemoteCollectionDriver().mongo.db;
var GridStore = Npm.require('mongodb').GridStore; //also need to add Npm.depends({mongodb:'2.0.13'}) in package.js

WebApp.connectHandlers.use('/uploadSomeWhere',function(req,res){
    //var start = Date.now()        
    var file = new GridStore(db,'filename','w').stream(true); //start the stream 

    file.on('error',function(e){...});
    file.on('end',function(){
        res.end(); //send end respone
        //console.log('Finish uploading, time taken: ' + Date.now() - start);
    });
    req.pipe(file);
});     

स्पष्टीकरण

क्लाइंट स्क्रिप्ट विकल्प 2 की तरह ही है।

Meteor 1.0.x mongo_driver.js अंतिम पंक्ति के अनुसार, MongoInternals नामक एक वैश्विक वस्तु उजागर हो गई है, आप GridStore के लिए आवश्यक वर्तमान डेटाबेस db ऑब्जेक्ट को वापस करने के लिए defaultRemoteCollectionDriver() को कॉल कर सकते हैं। संस्करण A में, GridStore को MongoInternals द्वारा भी उजागर किया जाता है। वर्तमान उल्का द्वारा उपयोग किया जाने वाला मोंगो v1.4.x

. है

फिर एक रूट के अंदर, आप var file =new GridStore(...) (API) को कॉल करके एक नया राइट ऑब्जेक्ट बना सकते हैं। फिर आप फ़ाइल खोलें और एक स्ट्रीम बनाएँ।

मैंने एक संस्करण बी भी शामिल किया है। इस संस्करण में, ग्रिडस्टोर को Npm.require('mongodb') के माध्यम से एक नई mongodb ड्राइव का उपयोग करके कहा जाता है, यह mongo इस लेखन के रूप में नवीनतम v2.0.13 है। नए एपीआई के लिए आपको फ़ाइल खोलने की आवश्यकता नहीं है, आप सीधे स्ट्रीम (सत्य) को कॉल कर सकते हैं और पाइपिंग शुरू कर सकते हैं

पेशेवरों

  1. विकल्प 2 के समान, ऐरेबफर का उपयोग करके भेजा गया, विकल्प 1 में बेस64 स्ट्रिंग की तुलना में कम ओवरहेड
  2. फ़ाइल नाम सेनिटेशन के बारे में चिंता करने की ज़रूरत नहीं है
  3. फाइल सिस्टम से पृथक्करण, अस्थायी डीआईआर को लिखने की कोई आवश्यकता नहीं है, डीबी का बैकअप लिया जा सकता है, प्रतिनिधि, शार्ड आदि
  4. किसी अन्य पैकेज को लागू करने की आवश्यकता नहीं है
  5. संग्रहणीय और gzipped किया जा सकता है
  6. सामान्य मोंगो संग्रह की तुलना में बहुत बड़े आकार में स्टोर करें
  7. मेमोरी ओवरलोड को कम करने के लिए पाइप का उपयोग करना

विपक्ष

  1. अस्थिर Mongo GridFS . मैंने संस्करण ए (मोंगो 1.x) और बी (मोंगो 2.x) शामिल किया। संस्करण ए में, बड़ी फ़ाइलों> 10 एमबी को पाइप करते समय, मुझे बहुत सारी त्रुटि मिली, जिसमें दूषित फ़ाइल, अधूरा पाइप शामिल है। इस समस्या को संस्करण बी में mongo 2.x का उपयोग करके हल किया गया है, उम्मीद है कि उल्का जल्द ही mongodb 2.x में अपग्रेड हो जाएगा
  2. एपीआई भ्रम . संस्करण ए में, आपको स्ट्रीम करने से पहले फ़ाइल को खोलने की आवश्यकता है, लेकिन संस्करण बी में, आप बिना कॉल किए स्ट्रीम कर सकते हैं। एपीआई दस्तावेज़ भी बहुत स्पष्ट नहीं है और Npm.require('fs') के साथ स्ट्रीम 100% सिंटैक्स विनिमेय नहीं है। fs में, आप file.on('finish') कहते हैं, लेकिन GridFS में आप file.on('end') पर कॉल करते हैं, जब लेखन खत्म/समाप्त होता है।
  3. ग्रिडएफएस लेखन परमाणुता प्रदान नहीं करता है, इसलिए यदि एक ही फ़ाइल में कई समवर्ती लेखन हैं, तो अंतिम परिणाम बहुत भिन्न हो सकता है
  4. गति . फ़ाइल सिस्टम की तुलना में Mongo GridFS बहुत धीमा है।

बेंचमार्क आप विकल्प 2 और विकल्प 3 में देख सकते हैं, मैंने var start =Date.now() शामिल किया है और अंत लिखते समय, मैं ms में समय को सांत्वना देता हूं। , नीचे परिणाम है। डुअल कोर, 4 जीबी रैम, एचडीडी, उबंटू 14.04 आधारित।

file size   GridFS  FS
100 KB      50      2
1 MB        400     30
10 MB       3500    100
200 MB      80000   1240

आप देख सकते हैं कि FS, GridFS की तुलना में बहुत तेज़ है। 200 एमबी की फ़ाइल के लिए, ग्रिडएफएस का उपयोग करने में ~80 सेकंड का समय लगता है लेकिन एफएस में केवल ~ 1 सेकंड। मैंने एसएसडी की कोशिश नहीं की है, परिणाम अलग हो सकता है। हालाँकि, वास्तविक जीवन में, बैंडविड्थ यह निर्धारित कर सकता है कि फ़ाइल को क्लाइंट से सर्वर तक कितनी तेजी से स्ट्रीम किया जाता है, 200 एमबी / सेकंड की स्थानांतरण गति प्राप्त करना सामान्य नहीं है। दूसरी ओर, स्थानांतरण गति ~2 एमबी/सेकंड (ग्रिडएफएस) अधिक आदर्श है।

निष्कर्ष

किसी भी तरह से यह व्यापक नहीं है, लेकिन आप तय कर सकते हैं कि आपकी ज़रूरत के लिए कौन सा विकल्प सबसे अच्छा है।

  • डीडीपी सबसे सरल है और मूल उल्का सिद्धांत से चिपक जाता है लेकिन डेटा अधिक भारी होता है, स्थानांतरण के दौरान संपीड़ित नहीं होता है, कैश करने योग्य नहीं होता है। लेकिन यह विकल्प अच्छा हो सकता है अगर आपको केवल छोटी फाइलों की जरूरत है।
  • XHR फाइल सिस्टम के साथ जुड़ा हुआ है 'पारंपरिक' तरीका है। स्थिर एपीआई, तेज, 'स्ट्रीम करने योग्य', संपीड़ित, कैश करने योग्य (ईटैग आदि), लेकिन एक अलग फ़ोल्डर में होना चाहिए
  • एक्सएचआर ग्रिडएफएस के साथ मिलकर , आपको प्रतिनिधि सेट, स्केलेबल, नो टचिंग फाइल सिस्टम डीआईआर, बड़ी फाइलें और कई फाइलों का लाभ मिलता है यदि फाइल सिस्टम संख्याओं को प्रतिबंधित करता है, कैशेबल कंप्रेसेबल भी। हालांकि, एपीआई अस्थिर है, आपको कई लेखन में त्रुटियां मिलती हैं, यह s..l..o..w..
  • है

उम्मीद है कि जल्द ही, उल्का डीडीपी gzip, कैशिंग आदि का समर्थन कर सकता है और GridFS तेज़ हो सकता है ...



  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. Node.js . के साथ SSL पर MongoDB से कनेक्ट करना

  2. MongoDB सामान्यीकरण, विदेशी कुंजी और शामिल होना

  3. Go . से MongoDB एक्सेस करना

  4. मोंगोडीबी निकालें ()

  5. MongoDB findOneAndUpdate ()