使用mongoose手动将唯一字符串标识符分发到mongoDB记录并检查重复项

时间:2018-06-08 20:46:21

标签: javascript node.js mongodb asynchronous mongoose

我试图在MEAN堆栈中开发一个系统,该系统应该包含存储在我的数据库中的Card模型。该模型应该有两个唯一的字段,对象ID和卡片代码,它们是一个长度为8个字符的字母数字字符串。我的架构类似于:

var cardSchema = new Schema({
  cod: {type: String, required: true, unique: true},
  titular: {type: String, required: true, index: true},
  balance: {type: Number, default: 500, min: 0, max: 500, required: true},
  lastCredited: {type: Date, default: Date.now(), required: true}
})

然后我正在创建我的对象:

cards.js:post create /

router.post('/create', function(req, res) {
  let card = new Card()
  card.cod = Card.generateCod()
  card.credit()
  if (/^[a-zA-Z\s]+$/.test(req.body.titular)) {
    card.titular = req.body.titular.toUpperCase()
  }
  else{
    res.status(406).send('Invalid name for titular')
    return
  }
  card.save(function (err, result) {
    if(err) res.status(406).send(err)
    else res.status(200).send(result)
  })
})

我的静态方法generateCod负责将随机字符串代码分发给卡片:

cardSchema.statics.generateCod = function(){
  let possible = "ABCDEFGHIJ0123456789"
  let cod = ''

  for (var i = 0; i < 8; i++) cod += possible.charAt(Math.floor(Math.random() * possible.length))
  return cod
}

然而,为了避免重复的代码,我正在寻找一些方法来检查生成的代码是否已经被使用,然后在肯定的情况下,我将生成另一个并重复该过程,在否定的情况下我只会返回代码。我找到的解决方案是向DB发送查询,将我的代码作为参数传递并检查响应的长度,如果长度等于0,则表示代码是唯一的。到目前为止一直很好,问题是,因为我的查询与代码异步发生,我不能简单地使用while或for循环来检查代码是否是唯一的并且在它是时断开循环,导致中断不会工作,循环会永远继续下去。我实际上是这样试过的:

while(true){
  for (var i = 0; i < 8; i++) cod += possible.charAt(Math.floor(Math.random() * possible.length))
  Card.find({cod: cod}, function(err, result) {
      if(result.length === 0) break
  })
}
return cod

我也尝试过:

while(true){
  for (var i = 0; i < 8; i++) cod += possible.charAt(Math.floor(Math.random() * possible.length))
  Card.find({cod: cod}, function(err, result) {
      if(result.length === 0) return cod
  })
}

甚至:

let unique = false
while(!unique){
  for (var i = 0; i < 8; i++) cod += possible.charAt(Math.floor(Math.random() * possible.length))
  Card.find({cod: cod}, function(err, result) {
      if(result.length === 0) unique = true
  })
}
return cod

但这些似乎都不起作用,循环总是永远存在。我对节点后端比较新,我觉得我错过了什么。有谁知道我如何从异步回调中打破外部循环?或者甚至是避免重复的另一种方法?我将不胜感激任何帮助!

1 个答案:

答案 0 :(得分:0)

Mongoose内置了对Promise的支持,因此您可以在此处使用async/await

cardSchema.statics.generateCod = async function() {
  let possible = "ABCDEFGHIJ0123456789";
  let cod = '';

  for (let i = 0; i < 8; i++) {
    cod += possible.charAt(Math.floor(Math.random() * possible.length));
  }

  let dup = await Card.findOne({cod: cod});

  if (dup) {
      return new Error("Can not generate COD");
  }

  return cod;
}

router.post('/create', async function(req, res) {
  let card = new Card()

  card.cod = await Card.generateCod()

  // ...
})

请注意我添加的所有asyncawait