- android - 多次调用 OnPrimaryClipChangedListener
- android - 无法更新 RecyclerView 中的 TextView 字段
- android.database.CursorIndexOutOfBoundsException : Index 0 requested, 光标大小为 0
- android - 使用 AppCompat 时,我们是否需要明确指定其 UI 组件(Spinner、EditText)颜色
我正在尝试实现一个简单的抽奖系统,其中我执行 GET/test,它返回一个随机用户,该用户 (1) 之前没有赢得过抽奖并且 (2) 在过去一小时内注册过。
在 Mongo 中,由于用户可以注册多个主题,因此可能有多个文档与用户关联。例如 {id: 1, name: 'John', subject: 'math',...}
和 {id: 1, name: 'John', subject: 'english',...}
。如果约翰被选中参加数学抽奖,那么他将没有资格参加所有后续抽奖,因此他无法多次获胜。本质上,抽奖者的 id 必须是唯一的。
我的问题是:我如何执行逻辑来检查约翰之前是否赢过?如果约翰已经获胜,我想从顶部重新启动 promise 链并再次执行 Math.random
直到选出唯一的获胜者。如果没有获胜者符合条件,那么我想返回 res.status(500)
。
app.get('/test', function(req, res, next) {
var currentTimestamp = new Date()
var oneHourAgo = new Date(currentTimestamp - oneHour)
var query = { "timeStamp": { $lte: currentTimestamp, $gte: oneHourAgo }, "isWinner": false }
var winna = {}
var winnerSelected = false
var collection = db.collection('entries');
while (!winnerSelected) { // how can I do this
collection.find(query).toArray().then( result => {
var winner = result[Math.floor(Math.random() * result.length)];
var query2 = {"id" : winner.id};
winna['id'] = winner.id
winna['name'] = winner.name
winna['subject'] = winner.subject
winna['timeStamp'] = winner.timeStamp
winna['isWinner'] = winner.isWinner
winna['raffleTimestamp'] = winner.raffleTimestamp
return collection.find(query2).toArray();
}).then( result => {
for (var i in result) { // a winner can enter the raffle for multiple subjects, but if he already won once, then I want to redraw by doing a rand function again
if (i.isWinner) { // until a winner who is eligible is found, or if none are eligible, res.status(500)
console.log("i already won")
break
// how do I make it go back to the beginning of the while loop and pick a new random winner?
}
}
console.log("unique winner")
winnerSelected = true // break out of while loop
var query3 = { id: winna.id, subject: winna.subject }
var raffleTimestamp = new Date()
var update = { $set: { isWinner: true, raffleTimestamp: raffleTimestamp } }
winna['isWinner'] = true
winna['raffleTimestamp'] = raffleTimestamp
res.send(winna) // send the winner with the updated fields to clientside
return collection.updateOne(query3, update); // update the isWinner and raffleTimestamp fields
}).then( result => {
res.status(200);
// res.send(result);
}).catch( err => {
console.log(err);
res.status(500);
});
}
})
最佳答案
简而言之,在这种情况下您实际上不需要这样做。但还有一个更长的解释。
如果您的 MongoDB 版本支持它,那么您可以简单地使用 $sample
在初始查询条件之后聚合管道以获得“随机”选择。
当然,在任何情况下,如果有人因为已经“获胜”而没有资格,那么只需将他们标记为这样,或者直接在另一组表格结果中标记。但这里“排除”的一般情况是简单地修改查询以将“获胜者”从可能的结果中排除。
但是,我实际上将至少在“现代”意义上演示“打破循环”,即使您实际上并不需要它来完成这里实际需要做的事情,这实际上是修改查询以排除。
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()
}
})()
当然,无论采用哪种方法,每次结果都是随机的,并且以前的“获胜者”被排除在实际查询本身的选择之外。这里的“循环中断”只是用来不断输出结果,直到不再有可能的获胜者为止。
<小时/>现代 Node.js 环境中的一般建议是内置的 async/await/yield
功能,现在在 v8.x.x 版本中默认启用。这些版本将于今年 10 月(截至撰写本文时)提供长期支持(LTS),并且按照我个人的“三个月规则”,那么任何新作品都应该基于当时流行的内容。
此处的替代案例通过 async.await
提供作为单独的库依赖项。或者使用“Bluebird”Promise.coroutine
作为单独的库依赖项,后一种情况是您可以交替使用 Promise.try
,但是如果您要包含一个库来获取该函数,那么您不妨使用另一个实现更现代语法方法的函数。
因此,“虽然”(双关语不是故意的)演示“打破 promise /回调”循环,但真正应该从这里去掉的主要内容是不同的查询过程,它实际上执行了在选择随机获胜者之前尝试在“循环”中实现的“排除”。
实际情况是数据决定了这一点。但整个示例至少展示了可以应用“选择”和“循环中断”的方法。
关于javascript - 如何有条件地从头开始重新启动 promise 链?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45123212/
我搜索了重启我的 android 应用程序的替代方法,但我发现重启的唯一方法是使用 Flex 构建. 我可以用 as3 flash 重启我的 android adobe air 应用程序吗?我该怎么做
我有一个学校评估,是为了制作一个 child 的拼写游戏,当玩家单击"is"时,它必须循环/重新启动。到目前为止,当我测试游戏时,询问玩家是否想再次玩的选项/easygui.buttonbox 以
在.yml文件中,我定义了:restart: always。是否可以将此重启创建为--force-recreate标志的等效项? 我的XVFB有问题,标准重启无法解决问题,但通过--force-rec
我正在尝试重新启动 while 循环。我已经声明了 boolean 类型的变量 keepGoing 。如果 int 变量 x 超出窗口,则 keepGoing 更改为 false。然后reset()方
如何使用 Cast SDK 或其他方式让我的应用以官方 Chromecast 应用的方式触发 Chromecast 重启? 如果是“否则”,Google Play 可能会对这种做法不友善吗? 最佳答案
运行/etc/init.d/postgresql restart有没有危险?我们刚刚发生了一些关系“消失”的事件,我运行了上述命令。刚刚被系统管理员骂了一顿,但是他没有解释为什么这是一件坏事。我确实将
是否可以重新启动 while 循环?我目前在 foreach 循环中存在一个 while 循环,并且每次都需要 while 语句从头开始。 $sql = mysqli_query($link, "SE
我有如下倒计时器: - (void)updateCounterLabel:(NSTimer *)theTimer { if(secondsLeft > 0 ){ secondsLeft
就像我在 python 中一样。 choice1 = raw_input('John Blue Green') if choice1 == 'A': print('blah') elif cho
我的游戏在 True 循环中运行一段时间,我希望能够要求用户“再玩一次?”我已经有了用于弹出文本的矩形的代码,但我需要一种方法让用户单击矩形或按 y 表示是,然后代码再次自行运行。 最佳答案 在您的主
我是 nginx 的初学者。我正在使用 Ubuntu 16.04。我按照步骤操作, sudo apt-get 更新。 sudo apt-get install nginx sudo apt-get 升
我需要使用 javascript 重放一个 css 转换。当我重置我的 div 的 css 样式并应用新的过渡时,没有任何反应...... 我认为这两个代码是在同一个执行框架中执行的,并且通过优化,它
所以我有这几行代码: string[] newData = File.ReadAllLines(fileName) int length = newData.Length; for (int i =
所以我有一个计时器,每 5 秒旋转一组图像。因此,我在文档启动时运行它。 $(document).ready(function() { var intervalID=setInterval(funct
好吧,我在重新启动 Apache 服务器时遇到了一些问题。我修改了服务器上的 ulimit 但我无法重新启动 httpd; 我在 CentOS 5.8 x64 上运行服务器. httpd -V 的输出
我在使用 docker 时遇到问题 docker ps不会返回并被卡住。 我发现做 docker service restart 之类的sudo service docker restart (htt
从 .net 代码停止和重新启动 Storyboard的正确方法是什么? 我想 ... myStory.Stop(this); 期望随后调用 .Begin(this);将从零开始从时间线重新开始,但
我有一个带有一些缓存后端的应用程序,我想在重新启动网络服务器时清除缓存。 在网络服务器(重新)启动时是否有 apache 配置指令或任何其他方式来执行 shell 脚本? 谢谢, 菲尔 正如一些答案已
我愿意在我的应用程序中添加一个按钮,单击该按钮将重新启动应用程序。我搜索了谷歌,但发现除了 this one 没有任何帮助.但是这里遵循的程序违反了 Java 的 WORA 概念。 是否还有其他以 J
我们目前遇到间歇性邮件队列中断。我是 seeking diagnostic help in another area . 同时,有没有办法在不重启整个服务的情况下重启CF邮件队列? CF8标准 Win
我是一名优秀的程序员,十分优秀!