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

बाहरी एपीआई कॉल के साथ लूपिंग परिणाम और FindOneAndUpdate

मुख्य बात जो आप वास्तव में याद कर रहे हैं वह यह है कि Mongoose API विधियां "वादे" , लेकिन ऐसा लगता है कि आप कॉलबैक का उपयोग करके दस्तावेज़ीकरण या पुराने उदाहरणों से कॉपी कर रहे हैं। इसका समाधान केवल वादों का उपयोग करने के लिए परिवर्तित करना है।

वादों के साथ काम करना

Model.find({},{ _id: 1, tweet: 1}).then(tweets => 
  Promise.all(
    tweets.map(({ _id, tweet }) => 
      api.petition(tweet).then(result =>   
       TweetModel.findOneAndUpdate({ _id }, { result }, { new: true })
         .then( updated => { console.log(updated); return updated })
      )
    )
  )
)
.then( updatedDocs => {
  // do something with array of updated documents
})
.catch(e => console.error(e))

कॉलबैक से सामान्य रूपांतरण के अलावा, मुख्य परिवर्तन Promise.all() से आउटपुट को हल करने के लिए Array.map() .find() के परिणामों पर संसाधित किया जा रहा है के लिए . के बजाय फंदा। यह वास्तव में आपके प्रयास में सबसे बड़ी समस्याओं में से एक है, क्योंकि के लिए वास्तव में नियंत्रित नहीं कर सकता जब async फ़ंक्शन हल हो जाते हैं। दूसरा मुद्दा "मिक्सिंग कॉलबैक" है, लेकिन यही वह है जिसे हम आम तौर पर केवल प्रॉमिस का उपयोग करके यहां संबोधित कर रहे हैं।

Array.map( ) हम वादा लौटाते हैं एपीआई कॉल से, findOneAndUpdate() तक जंजीर से बंधी हुई जो वास्तव में दस्तावेज़ को अद्यतन कर रहा है। हम नया:सच . का भी उपयोग करते हैं वास्तव में संशोधित दस्तावेज़ वापस करने के लिए।

Promise.all() परिणामों की एक सरणी को हल करने और वापस करने के लिए "वादे की सरणी" की अनुमति देता है। इन्हें आप updatedDocs . के रूप में देखते हैं . यहां एक और फायदा यह है कि आंतरिक विधियां "समानांतर" में आग लगती हैं और श्रृंखला में नहीं। इसका आमतौर पर एक तेज़ समाधान होता है, हालांकि इसमें कुछ और संसाधन लगते हैं।

यह भी ध्यान दें कि हम { _id:1, ट्वीट:1 } के "प्रक्षेपण" का उपयोग करते हैं केवल उन दो क्षेत्रों को Model.find() से लौटाने के लिए परिणाम क्योंकि शेष कॉल में केवल वही उपयोग किए जाते हैं। जब आप अन्य मानों का उपयोग नहीं करते हैं तो यह प्रत्येक परिणाम के लिए पूरे दस्तावेज़ को वापस करने पर बचाता है।

आप बस Promise<लौटा सकते हैं /कोड> findOneAndUpdate() से , लेकिन मैं सिर्फ console.log() . में जोड़ रहा हूं ताकि आप देख सकें कि उस समय आउटपुट सक्रिय हो रहा है।

सामान्य उत्पादन उपयोग इसके बिना करना चाहिए:

Model.find({},{ _id: 1, tweet: 1}).then(tweets => 
  Promise.all(
    tweets.map(({ _id, tweet }) => 
      api.petition(tweet).then(result =>   
       TweetModel.findOneAndUpdate({ _id }, { result }, { new: true })
      )
    )
  )
)
.then( updatedDocs => {
  // do something with array of updated documents
})
.catch(e => console.error(e))

एक और "ट्वीक" Promise के "ब्लूबर्ड" कार्यान्वयन का उपयोग करना हो सकता है। नक्शा () , जो दोनों आम को जोड़ती है। Array.map() करने के लिए Promise (ओं) समानांतर कॉल चलाने की "संगामिति" को नियंत्रित करने की क्षमता के साथ कार्यान्वयन:

const Promise = require("bluebird");

Model.find({},{ _id: 1, tweet: 1}).then(tweets => 
  Promise.map(tweets, ({ _id, tweet }) => 
    api.petition(tweet).then(result =>   
      TweetModel.findOneAndUpdate({ _id }, { result }, { new: true })
    ),
    { concurrency: 5 }
  )
)
.then( updatedDocs => {
  // do something with array of updated documents
})
.catch(e => console.error(e))

अनुक्रम में "समानांतर" का विकल्प निष्पादित किया जाएगा। इस पर विचार किया जा सकता है यदि बहुत अधिक परिणाम डेटाबेस में वापस लिखने के लिए बहुत अधिक API कॉल और कॉल का कारण बनते हैं:

Model.find({},{ _id: 1, tweet: 1}).then(tweets => {
  let updatedDocs = [];
  return tweets.reduce((o,{ _id, tweet }) => 
    o.then(() => api.petition(tweet))
      .then(result => TweetModel.findByIdAndUpdate(_id, { result }, { new: true })
      .then(updated => updatedDocs.push(updated))
    ,Promise.resolve()
  ).then(() => updatedDocs);
})
.then( updatedDocs => {
  // do something with array of updated documents
})
.catch(e => console.error(e))

वहां हम Array का उपयोग कर सकते हैं। कम करें () वादों को एक साथ "श्रृंखला" करने के लिए उन्हें क्रमिक रूप से हल करने की अनुमति देता है। ध्यान दें कि परिणामों की सरणी को दायरे में रखा जाता है और अंतिम .then() . के साथ बदल दिया जाता है जुड़ी हुई शृंखला के अंत में जोड़ा जाता है क्योंकि आपको उस "श्रृंखला" के विभिन्न बिंदुओं पर वादों को हल करने के परिणामों को "एकत्रित" करने के लिए ऐसी तकनीक की आवश्यकता होती है।

Async/प्रतीक्षा

आधुनिक वातावरण में NodeJS V8.x से जो वास्तव में वर्तमान LTS रिलीज़ है और अभी कुछ समय के लिए है, आपके पास वास्तव में async/await के लिए समर्थन है . इससे आप अपने प्रवाह को अधिक स्वाभाविक रूप से लिख सकते हैं

try {
  let tweets = await Model.find({},{ _id: 1, tweet: 1});

  let updatedDocs = await Promise.all(
    tweets.map(({ _id, tweet }) => 
      api.petition(tweet).then(result =>   
        TweetModel.findByIdAndUpdate(_id, { result }, { new: true })
      )
    )
  );

  // Do something with results
} catch(e) {
  console.error(e);
}

या संभवतः क्रमिक रूप से संसाधित करें, यदि संसाधन एक समस्या है:

try {
  let cursor = Model.collection.find().project({ _id: 1, tweet: 1 });

  while ( await cursor.hasNext() ) {
    let { _id, tweet } = await cursor.next();
    let result = await api.petition(tweet);
    let updated = await TweetModel.findByIdAndUpdate(_id, { result },{ new: true });
    // do something with updated document
  }

} catch(e) {
  console.error(e)
}

यह भी ध्यान दें कि findByIdAndUpdate() _id . के मिलान के रूप में भी इस्तेमाल किया जा सकता है पहले से ही निहित है इसलिए आपको पहले तर्क के रूप में संपूर्ण क्वेरी दस्तावेज़ की आवश्यकता नहीं है।

बल्क राइट

अंतिम नोट के रूप में यदि आपको वास्तव में प्रतिक्रिया में अद्यतन दस्तावेज़ों की आवश्यकता नहीं है, तो बल्कराइट () बेहतर विकल्प है और लिखने को आम तौर पर एक ही अनुरोध में सर्वर पर संसाधित करने की अनुमति देता है:

Model.find({},{ _id: 1, tweet: 1}).then(tweets => 
  Promise.all(
    tweets.map(({ _id, tweet }) => api.petition(tweet).then(result => ({ _id, result }))
  )
).then( results =>
  Tweetmodel.bulkWrite(
    results.map(({ _id, result }) => 
      ({ updateOne: { filter: { _id }, update: { $set: { result } } } })
    )
  )
)
.catch(e => console.error(e))

या async/प्रतीक्षा . के माध्यम से वाक्य रचना:

try {
  let tweets = await Model.find({},{ _id: 1, tweet: 1});

  let writeResult = await Tweetmodel.bulkWrite(
    (await Promise.all(
      tweets.map(({ _id, tweet }) => api.petition(tweet).then(result => ({ _id, result }))
    )).map(({ _id, result }) =>
      ({ updateOne: { filter: { _id }, update: { $set: { result } } } })
    )
  );
} catch(e) {
  console.error(e);
}

ऊपर दिखाए गए सभी संयोजनों में बहुत अधिक विविधता हो सकती है जैसे bulkWrite() विधि निर्देशों की एक "सरणी" लेती है, इसलिए आप उपरोक्त प्रत्येक विधि में से संसाधित API कॉल से उस सरणी का निर्माण कर सकते हैं।




  1. Redis
  2.   
  3. MongoDB
  4.   
  5. Memcached
  6.   
  7. HBase
  8.   
  9. CouchDB
  1. उन दस्तावेज़ों के लिए क्वेरी जिनमें किसी दिए गए मान का आंतरिक उप-क्षेत्र है

  2. कर्सर.ऑब्जर्व कैसे काम करता है और एक से अधिक इंस्टेंस चलने से कैसे बचें?

  3. छवियाँ संग्रहीत करना:MongoDb बनाम फ़ाइल सिस्टम

  4. MongoDb - एक ऐरे को क्वेरी करें

  5. MongoDB में सरणी को ऑब्जेक्ट में कैसे बदलें