संक्षेप में, आपको वास्तव में इस मामले में ऐसा करने की आवश्यकता नहीं है। लेकिन एक लंबी व्याख्या है।
यदि आपका MongoDB संस्करण इसका समर्थन करता है, तो आप बस का उपयोग कर सकते हैं। $नमूना
"यादृच्छिक" चयन प्राप्त करने के लिए आपकी प्रारंभिक क्वेरी शर्तों के बाद एकत्रीकरण पाइपलाइन।
बेशक किसी भी मामले में, अगर कोई पात्र नहीं है क्योंकि वे पहले से ही "जीत गए" हैं तो बस उन्हें इस तरह चिह्नित करें, या तो सीधे सारणीबद्ध परिणामों के दूसरे सेट में। लेकिन यहां "बहिष्करण" का सामान्य मामला संभावित परिणामों से "विजेताओं" को बाहर करने के लिए केवल क्वेरी को संशोधित करना है।
हालांकि, मैं वास्तव में कम से कम "आधुनिक" अर्थ में "लूप को तोड़ना" प्रदर्शित करूंगा, भले ही आपको वास्तव में इसकी आवश्यकता नहीं है, जो आपको वास्तव में यहां करने की आवश्यकता है, जो वास्तव में इसके बजाय बाहर करने के लिए क्वेरी को संशोधित करता है।
const MongoClient = require('mongodb').MongoClient,
whilst = require('async').whilst,
BPromise = require('bluebird');
const users = [
'Bill',
'Ted',
'Fred',
'Fleur',
'Ginny',
'Harry'
];
function log (data) {
console.log(JSON.stringify(data,undefined,2))
}
const oneHour = ( 1000 * 60 * 60 );
(async function() {
let db;
try {
db = await MongoClient.connect('mongodb://localhost/raffle');
const collection = db.collection('users');
// Clean data
await collection.remove({});
// Insert some data
let inserted = await collection.insertMany(
users.map( name =>
Object.assign({ name },
( name !== 'Harry' )
? { updated: new Date() }
: { updated: new Date( new Date() - (oneHour * 2) ) }
)
)
);
log(inserted);
// Loop with aggregate $sample
console.log("Aggregate $sample");
while (true) {
let winner = (await collection.aggregate([
{ "$match": {
"updated": {
"$gte": new Date( new Date() - oneHour ),
"$lt": new Date()
},
"isWinner": { "$ne": true }
}},
{ "$sample": { "size": 1 } }
]).toArray())[0];
if ( winner !== undefined ) {
log(winner); // Picked winner
await collection.update(
{ "_id": winner._id },
{ "$set": { "isWinner": true } }
);
continue;
}
break;
}
// Reset data state
await collection.updateMany({},{ "$unset": { "isWinner": "" } });
// Loop with random length
console.log("Math random selection");
while (true) {
let winners = await collection.find({
"updated": {
"$gte": new Date( new Date() - oneHour ),
"$lt": new Date()
},
"isWinner": { "$ne": true }
}).toArray();
if ( winners.length > 0 ) {
let winner = winners[Math.floor(Math.random() * winners.length)];
log(winner);
await collection.update(
{ "_id": winner._id },
{ "$set": { "isWinner": true } }
);
continue;
}
break;
}
// Reset data state
await collection.updateMany({},{ "$unset": { "isWinner": "" } });
// Loop async.whilst
console.log("async.whilst");
// Wrap in a promise to await
await new Promise((resolve,reject) => {
var looping = true;
whilst(
() => looping,
(callback) => {
collection.find({
"updated": {
"$gte": new Date( new Date() - oneHour ),
"$lt": new Date()
},
"isWinner": { "$ne": true }
})
.toArray()
.then(winners => {
if ( winners.length > 0 ) {
let winner = winners[Math.floor(Math.random() * winners.length)];
log(winner);
return collection.update(
{ "_id": winner._id },
{ "$set": { "isWinner": true } }
);
} else {
looping = false;
return
}
})
.then(() => callback())
.catch(err => callback(err))
},
(err) => {
if (err) reject(err);
resolve();
}
);
});
// Reset data state
await collection.updateMany({},{ "$unset": { "isWinner": "" } });
// Or synatax for Bluebird coroutine where no async/await
console.log("Bluebird coroutine");
await BPromise.coroutine(function* () {
while(true) {
let winners = yield collection.find({
"updated": {
"$gte": new Date( new Date() - oneHour ),
"$lt": new Date()
},
"isWinner": { "$ne": true }
}).toArray();
if ( winners.length > 0 ) {
let winner = winners[Math.floor(Math.random() * winners.length)];
log(winner);
yield collection.update(
{ "_id": winner._id },
{ "$set": { "isWinner": true } }
);
continue;
}
break;
}
})();
} catch(e) {
console.error(e)
} finally {
db.close()
}
})()
और निश्चित रूप से किसी भी दृष्टिकोण के साथ परिणाम हर बार यादृच्छिक होते हैं और पिछले "विजेताओं" को वास्तविक क्वेरी में ही चयन से बाहर रखा जाता है। यहां "लूप ब्रेक" का उपयोग केवल परिणामों को आउटपुट करने के लिए किया जाता है जब तक कि कोई और संभावित विजेता न हो।
"लूप ब्रेकिंग" विधियों पर एक नोट
आधुनिक नोड.जेएस परिवेशों में सामान्य अनुशंसा को async/await/yield
में बनाया जाना चाहिए सुविधाओं को अब v8.x.x रिलीज़ में डिफ़ॉल्ट रूप से चालू के रूप में शामिल किया गया है। ये संस्करण इस साल अक्टूबर में (लेखन के रूप में) और मेरे अपने व्यक्तिगत "तीन महीने के नियम" के अनुसार दीर्घकालिक समर्थन (एलटीएस) को प्रभावित करेंगे, फिर कोई भी नया काम उन चीजों पर आधारित होना चाहिए जो उस समय वर्तमान में होंगे।
यहां वैकल्पिक मामले async.await
के माध्यम से प्रस्तुत किए गए हैं
एक अलग पुस्तकालय निर्भरता के रूप में। या अन्यथा "ब्लूबर्ड" Promise.coroutineका उपयोग करके एक अलग पुस्तकालय निर्भरता के रूप में कोड>
, बाद वाला मामला यह है कि आप वैकल्पिक रूप से Promise.tryका उपयोग कर सकते हैं। कोड>
, लेकिन यदि आप उस फ़ंक्शन को प्राप्त करने के लिए एक पुस्तकालय शामिल करने जा रहे हैं, तो आप अन्य फ़ंक्शन का भी उपयोग कर सकते हैं जो अधिक आधुनिक वाक्यविन्यास दृष्टिकोण को लागू करता है।
तो "एक वादा/कॉलबैक तोड़ना" प्रदर्शित करते हुए "जबकि" (सजा का इरादा नहीं है) लूप, मुख्य बात जो वास्तव में यहां से हटा दी जानी चाहिए वह अलग क्वेरी प्रक्रिया है, जो वास्तव में "बहिष्करण" करती है जिसे "लूप" में लागू करने का प्रयास किया जा रहा था जब तक कि यादृच्छिक विजेता का चयन नहीं किया गया था।
वास्तविक मामला यह है कि डेटा इसे सबसे अच्छा निर्धारित करता है। लेकिन पूरा उदाहरण कम से कम ऐसे तरीके दिखाता है कि चयन और "लूप ब्रेक" दोनों को लागू किया जा सकता है।