不,我真的很同意它的最好的處理問題,但作爲一個學術練習,它實際上只是一個將您的名字生成包裹在遞歸函數中的問題,您可以在找到匹配項時提供遞增的長度參數。
這裏唯一真正的約束是你的函數本身應該返回一個Promise
,無論是結果還是對遞歸調用本身。
對於懶惰,你的執行將是這樣的:使用async/await
關鍵字
create: (req, res, next) => {
const { title, desc, img } = req.body;
// Recursive function definition
function generateName(title, desc, img, randomLength) {
const defaultLength = 8;
randomLength = randomLength || defaultLength;
let name = randomstring.generate({
length: randomLength, charset: "alphabetic" });
return SpoofItem.count({ name }).then(count => {
if (count > 0) {
randomLength++;
return generateName(title, desc, img, randomLength);
} else {
return SpoofItem.create({ title, desc, img, name });
}
});
}
generateName(title, desc, img).then(spoofItem => res.json(spoofItem))
.catch(error => res.status(500).json({ error }));
}
或許有點更現代:
create: async (req, res, next) => { // marked as async
const { title, desc, img } = req.body;
// Recursive function definition also marked as async
async function generateName(title, desc, img, randomLength) {
const defaultLength = 8;
randomLength = randomLength || defaultLength;
let name = randomstring.generate({
length: randomLength, charset: "alphabetic" });
let count = await SpoofItem.count({ name });
if (count > 0) {
randomLength++;
return generateName(title, desc, img, randomLength);
} else {
return SpoofItem.create({ title, desc, img, name });
}
}
// try/catch instead of .catch()
try {
let spoofItem = await generateName(title, desc, img);
res.json(spoofItem);
} catch(error) {
res.status(500).json({ error });
}
}
最大的變化在這裏是把重複的邏輯會以遞歸方式存在於實際進行遞歸調用的函數中。請注意0的「可選」參數,因爲當它沒有提供時,您將使用「默認」。此外,實際的數據庫寫入會在此函數內移動,因此其他將寫入的值也會傳遞到該函數中。
基本思想是給定參數名稱生成,然後在數據庫中查找該名稱。使用.count()
是最有效的方法,因爲值在遊標狀態中可用,而不實際檢索除統計本身之外的任何數據。
該操作返回Promise
,因此您要麼繼續使用.then()
,要麼使用await
。然後它就是基於返回的「count」的簡單分支。
要不就是價值發現和randomLength
量就會增,並通過回遞歸調用,或.create()
方法被調用(基本上new SpoofItem()
和.save()
一)實際編寫了「獨一無二」的價值。無論哪種方式,返回Promise
。
在相同的情況下,還可以根據需要通過.then()
或await
等待解析「包裝」功能。 .catch()
或catch
涵蓋了可能的錯誤。
同樣,這些「錯誤」可能「應該」被委託給next
處理程序,但這不是真正的問題。
作爲更完整的演示,如下自包含在任一種形式應該表現出字符串長度列表遞增,主要是由於初始短的長度,其是某些吸引重複:
要麼標誌着與async
功能和內部呼叫使用await
:
const randomstring = require('randomstring'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const testSchema = new Schema({
name: String
});
const Test = mongoose.model('Test', testSchema);
async function generateName(randomLength) {
const defaultLength = 1;
randomLength = randomLength || defaultLength;
let name = randomstring.generate({
length: randomLength, charset: "alphabetic" });
let count = await Test.count({ name });
if (count > 0) {
randomLength++;
return generateName(randomLength);
} else {
return Test.create({ name });
}
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clear existing data
await Test.remove();
// Loop random generation
for (let x = 1; x <= 1000; x++) {
await generateName();
}
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})();
,或以傳統.then()
:
const randomstring = require('randomstring'),
mongoose = require('mongoose'),
Schema = mongoose.Schema;
mongoose.Promise = global.Promise;
mongoose.set('debug',true);
const uri = 'mongodb://localhost/test',
options = { useMongoClient: true };
const testSchema = new Schema({
name: String
});
const Test = mongoose.model('Test', testSchema);
function generateName(randomLength) {
const defaultLength = 1;
randomLength = randomLength || defaultLength;
let name = randomstring.generate({
length: randomLength, charset: "alphabetic" });
return Test.count({ name }).then(count => {
if (count > 0) {
randomLength++;
return generateName(randomLength);
} else {
return Test.create({ name });
}
});
}
(async function() {
try {
const conn = await mongoose.connect(uri,options);
// Clear existing data
await Test.remove();
// Loop random generation
for (let x = 1; x <= 1000; x++) {
await generateName();
}
} catch(e) {
console.error(e);
} finally {
mongoose.disconnect();
}
})();
任何一種情況下都會生成1000個「唯一」隨機字符串,其中在給定長度的碰撞可能性的情況下,元素的數量將推送到3
。
可選地在架構上添加一個「唯一」約束來「證明」這些值實際上是「唯一」的,但這基本上是.count()
操作的要點,所以它只是額外的「強制」當由其他現有的邏輯來管理時是必需的。
爲什麼你需要從8到9?底線是在8個位置上,當然只有可能產生的有限數量的組合。查詢數據庫的現有值並不一定意味着在找到匹配項時已經使用了這些可能的組合。如果你想要一個隨機標記,那麼你應該選擇一個具有足夠可能值的長度並堅持下去。或者甚至考慮你的用例,並研究出已經保證唯一性的東西就足夠了(即'ObjectId')。哪種方法比遞歸查詢更好。 –
我完全明白你的意思,並深深地考慮了這一點。名稱var將用於URL的末尾,否則將使用objectID。雖然它發生的可能性可能不會,但我想調整可擴展性以防萬一。 – brandenbuilds