我试图在我的数据库中扫描整个树,为每个项目寻找两个属性('title' 和 'id'),然后我需要检查当前表下面是否有一个链接的数据库表,如果所以,我需要对该表执行相同的操作。
获得整个树后,我需要将它们插入到主变量中,然后我可以将其导入到整个 Web 应用程序的其他位置。
(我很确定我正在重新发明轮子。我已经搜索了 Sequelize 文档,但是如果有一个简单的解决方案,我没有看到它。)
这是我当前代码的相关部分(它还没有完全工作,但应该给出想法)。
( You can find the full project repository by clicking this link here. )
``
const buildTopicTreeFromCurrentDatabase = (callback) => {
let topicTree = [];
let isFinished = false;
const isSearchFinished = new Emitter();
console.log(`emitter created`);
isSearchFinished.on('finished', () => {
console.log(`the search is done`);
if (isFinished = true) {
callback(null, this.primaryTopicsShort)
};
});
/* need to go back and refactor -- violates DRY */
this.primaryTopicsShort = [];
PrimaryTopic.all()
.then((primaryTopics) => {
if (primaryTopics.length === 0) {
return callback('no Primary Topics defined');
}
for (let i = 0; i < primaryTopics.length; i++) {
this.primaryTopicsShort[i] = {
title: primaryTopics[i].title,
id: primaryTopics[i].id,
secondaryTopics: []
};
PrimaryTopic.findById(this.primaryTopicsShort[i].id, {
include: [{
model: SecondaryTopic,
as: 'secondaryTopics'
}]
})
.then((currentPrimaryTopic) => {
if (currentPrimaryTopic.secondaryTopics.length !== 0) {
for (let j = 0; j < currentPrimaryTopic.secondaryTopics.length; j++) {
this.primaryTopicsShort[i].secondaryTopics[j] = {
title: currentPrimaryTopic.secondaryTopics[j].title,
id: currentPrimaryTopic.secondaryTopics[j].id,
thirdTopics: []
};
SecondaryTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].id, {
include: [{
model: ThirdTopic,
as: 'thirdTopics'
}]
})
.then((currentSecondaryTopic) => {
if (currentPrimaryTopic.secondaryTopics.length - 1 === j) {
isSearchFinished.emit('finished');
}
if (currentSecondaryTopic.thirdTopics.length !== 0) {
for (let k = 0; k < currentSecondaryTopic.thirdTopics.length; k++) {
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k] = {
title: currentSecondaryTopic.thirdTopics[k].title,
id: currentSecondaryTopic.thirdTopics[k].id,
fourthTopics: []
};
ThirdTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].id, {
include: [{
model: FourthTopic,
as: 'fourthTopics'
}]
})
.then((currentThirdTopics) => {
if (currentThirdTopics.fourthTopics.length !== 0) {
for (let l = 0; l < currentThirdTopics.fourthTopics.length; l++) {
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[k] = {
title: currentThirdTopics.fourthTopics[l].title,
id: currentThirdTopics.fourthTopics[l].id,
fifthTopics: []
}
FourthTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[l].id, {
include: [{
model: FifthTopic,
as: 'fifthTopics'
}]
})
.then((currentFourthTopics) => {
if (currentFourthTopics.fifthTopics.length !== 0) {
for (let m = 0; m < currentFourthTopics.fifthTopics.length; m++) {
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[k].fifthTopics[m] = {
title: currentFourthTopics.fifthTopics[m].title,
id: currentFourthTopics.fifthTopics[m].id
}
}
}
})
.catch((err) => {
callback(err);
});
}
}
})
.catch((err) => {
callback(err)
});
}
}
})
.catch((err) => {
callback(err);
})
}
}
})
.catch((err) => {
callback(err);
})
}
})
.catch((err) => {
callback(err);
});
};
这段代码有几个问题。
首先,我需要使用 DRY 和递归解决方案,因为数据库结构将来可能会发生变化。
其次,我在“完成”的发射器上玩了很多,但我还没有想出如何放置它,以便在搜索数据库结束时发出事件,而且我也不会多次循环返回数据库。
我一直在研究以下递归解决方案,但时间一直在延长,我觉得我一无所获。
const buildDatabaseNames = (DatabaseNameStr, callback) => {
let camelSingular = DatabaseNameStr.slice(0,1);
camelSingular = camelSingular.toLowerCase();
camelSingular = camelSingular + DatabaseNameStr.slice(1, DatabaseNameStr.length);
let camelPlural = DatabaseNameStr.slice(0,1);
camelPlural = camelPlural.toLowerCase();
camelPlural = camelPlural + DatabaseNameStr.slice(1, DatabaseNameStr.length) + 's';
let databaseNameStr = `{ "capsSingular": ${"\"" + DatabaseNameStr + "\""}, "capsPlural": ${"\"" + DatabaseNameStr + 's' + "\""}, "camelSingular": ${"\"" + camelSingular + "\""}, "camelPlural": ${"\"" + camelPlural + "\""} }`;
let names = JSON.parse(databaseNameStr);
return callback(names);
};
const isAnotherDatabase = (DatabaseName, id, NextDatabaseName) => {
DatabaseName.findById({
where: {
id: id
}
})
.then((res) => {
if (typeof res.NextDatabaseName === undefined) {
return false;
} else if (res.NextDatabaseName.length === 0) {
return false;
} else {
return true;
}
})
.catch((err) => {
console.error(err);
process.exit();
});
};
const searchDatabase = (first, i, current, next, list, callback) => {
if (typeof first === 'string') {
first = buildDatabaseNames(first);
current = buildDatabaseNames(current);
next = buildDatabaseNames(next);
}
if (first === current) {
this.first = current;
let topicTree = [];
const isSearchFinished = new Emitter();
console.log(`emitter created`);
isSearchFinished.on('finished', () => {
console.log(`the search is done`);
callback(null, this.primaryTopicsShort);
});
}
current.CapsSingular.all()
.then((res) => {
current.camelPlural = res;
if (if current.camelPlural.length !== 0) {
for (let j = 0; j < currentParsed.camelPlural.length; j++) {
if (first === current) {
this.first[i].current[j].title = current.camelPlural[j].title,
this.first[i].current[j].id = current.camelPlural[j].id
next.camelSingular = []
} else {
this.first[i]..current[j].title = current.camelPlural[j].title,
this.first[i].id = current.camelPlural[j].id,
next.camelSingular = []
}
let isNext = isAnotherDatabase(current.)
searchDatabase(null, j, next, list[i + 1], list, callback).bind(this);
}
} else {
callback(null, this.first);
}
})
.catch((err) => {
callback(err);
});
};
我决定停下来寻求帮助,因为我刚刚意识到为了使每次递归迭代的属性(
this.first[i].current[j].title = current.camelPlural[j].title
)准确,我必须执行 JSON.stringify
,更改下一次迭代的字符串,放置所有必需的迭代 it into 一个变量,将其传递给下一个递归,然后再次执行 JSON.parse
。好像我把这复杂得可笑?任何帮助表示赞赏,谢谢。
最佳答案
虽然我无法做出递归的通用解决方案,但我至少找到了一些结果。
const buildTopicTreeFromCurrentDatabase = (callback) => {
let topicTree = [];
const isSearchFinished = new Emitter();
isSearchFinished.on('finished', () => {
if (isFinished === 0) {
callback(null, this.primaryTopicsShort);
};
});
/* need to go back and refactor -- violates DRY */
this.primaryTopicsShort = [];
let isFinished = 0;
isFinished = isFinished++;
PrimaryTopic.all()
.then((primaryTopics) => {
isFinished = isFinished + primaryTopics.length;
if (primaryTopics.length === 0) {
return callback('no Primary Topics defined');
}
for (let i = 0; i < primaryTopics.length; i++) {
if (i === 0) {
var isLastPrimary = false;
};
this.primaryTopicsShort[i] = {
title: primaryTopics[i].title,
id: primaryTopics[i].id,
secondaryTopics: []
};
PrimaryTopic.findById(this.primaryTopicsShort[i].id, {
include: [{
model: SecondaryTopic,
as: 'secondaryTopics'
}]
})
.then((currentPrimaryTopic) => {
isFinished = isFinished - 1 + currentPrimaryTopic.secondaryTopics.length;
if (i === primaryTopics.length - 1) {
isLastPrimary = true;
};
if (currentPrimaryTopic.secondaryTopics.length === 0 && isLastPrimary) {
isSearchFinished.emit('finished');
} else if (currentPrimaryTopic.secondaryTopics.length !== 0) {
for (let j = 0; j < currentPrimaryTopic.secondaryTopics.length; j++) {
if (j === 0) {
var isLastSecondary = false;
}
this.primaryTopicsShort[i].secondaryTopics[j] = {
title: currentPrimaryTopic.secondaryTopics[j].title,
id: currentPrimaryTopic.secondaryTopics[j].id,
thirdTopics: []
};
SecondaryTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].id, {
include: [{
model: ThirdTopic,
as: 'thirdTopics'
}]
})
.then((currentSecondaryTopic) => {
isFinished = isFinished - 1 + currentSecondaryTopic.thirdTopics.length;
if (j === currentPrimaryTopic.secondaryTopics.length - 1) {
isLastSecondary = true;
}
if (currentSecondaryTopic.thirdTopics.length === 0 && isLastPrimary && isLastSecondary) {
isSearchFinished.emit('finished');
} else if (currentSecondaryTopic.thirdTopics.length !== 0) {
for (let k = 0; k < currentSecondaryTopic.thirdTopics.length; k++) {
if (k === 0) {
var isLastThird = false;
};
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k] = {
title: currentSecondaryTopic.thirdTopics[k].title,
id: currentSecondaryTopic.thirdTopics[k].id,
fourthTopics: []
};
ThirdTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].id, {
include: [{
model: FourthTopic,
as: 'fourthTopics'
}]
})
.then((currentThirdTopic) => {
isFinished = isFinished - 1 + currentThirdTopic.fourthTopics.length;
if (k === currentSecondaryTopic.thirdTopics.length - 1) {
isLastThird = true;
};
if (currentThirdTopic.fourthTopics.length === 0 && isLastPrimary && isLastSecondary && isLastThird) {
isSearchFinished.emit('finished');
} else if (currentThirdTopic.fourthTopics.length !== 0) {
for (let l = 0; l < currentThirdTopic.fourthTopics.length; l++) {
if (l = 0) {
var isLastFourth = false;
}
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[k] = {
title: currentThirdTopic.fourthTopics[l].title,
id: currentThirdTopic.fourthTopics[l].id,
fifthTopics: []
}
FourthTopic.findById(this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[l].id, {
include: [{
model: FifthTopic,
as: 'fifthTopics'
}]
})
.then((currentFourthTopics) => {
isFinished = isFinished - 1 + currentFourthTopics.fifthTopics.length;
if (l = currentThirdTopic.fourthTopics.length - 1) {
isLastFourth = true;
}
if (currentFourthTopic.fifthTopics.length === 0 && isLastPrimary && isLastSecondary && isLastThird && isLastFourth) {
isSearchFinished.emit('finished');
} else if (currentFourthTopic.fifthTopics.length !== 0) {
for (let m = 0; m < currentFourthTopic.fifthTopics.length; m++) {
if (m = 0) {
var isLastFifth = false;
}
if (m === currentFourthTopic.fifthTopics.length - 1) {
isLastFifth = true;
}
this.primaryTopicsShort[i].secondaryTopics[j].thirdTopics[k].fourthTopics[k].fifthTopics[m] = {
title: currentFourthTopic.fifthTopics[m].title,
id: currentFourthTopic.fifthTopics[m].id
};
if (isLastPrimary === true && isLastSecondary === true && isLastThird === true && isLastFourth === true && isLastFifth === true) {
isFinished = isFinished - 1;
isSearchFinished.emit('finished');
};
}
}
})
.catch((err) => {
callback(err);
});
}
}
})
.catch((err) => {
callback(err)
});
}
}
})
.catch((err) => {
callback(err);
})
}
}
})
.catch((err) => {
callback(err);
});
}
})
.catch((err) => {
callback(err);
});
};
我最终了解到我面临的问题的根源在于数据库调用的异步特性。
为了防止最后的
callback
在所有调用完成之前被触发,我使用了一种叫做信号量的东西。这是其他语言中经常使用的东西,但在 JavaScript 中不经常使用(所以我听说)。您可以通过查看变量
isFinished
来了解它是如何工作的。该值从零开始,并随着它从数据库中检索到的每个条目而增加。当它完成处理数据时,代码从总值中减去 1
。最后的 callback
事件(在发射器中)只有在 isFinished
值返回零时才能关闭。这不是最优雅的解决方案。正如@Timshel 所说,最好不要设计这个没有这么多不同表的数据库部分。
但是这个解决方案现在就可以了。
谢谢。
关于javascript - 如何查询几乎整个 postgresql 数据库的每个项目的属性? (使用 sequelize 和 Node.js),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51810083/