javascript - 如何查询几乎整个 postgresql 数据库的每个项目的属性? (使用 sequelize 和 Node.js)

标签 javascript node.js postgresql recursion sequelize.js

我试图在我的数据库中扫描整个树,为每个项目寻找两个属性('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/

相关文章:

javascript - Google Maps API - 打开的信息窗口始终相同

JavaScript 特定函数提升

javascript - Mongodb数据插入问题

javascript - 如何从 angularjs/express 应用程序中的表单获取数据

spring JDBC 无法连接到 postgres 数据库,但普通 JDBC 可以连接

node.js - 如何使用 jest 在 Node.js 中模拟 postgresql (pg)

javascript - RequireJS 异步加载导致用户体验(UX)不佳?

node.js - 无法安装 Node 7.5.0

sql - crosstab postgres - 行到列

javascript - 将 Canvas 显示为 gif 以进行视频预览