如何保存来自 model.find({}) 函数的数据?

How do I save data from a model.find({}) function?

我正在尝试使用 Mongoose 和 Express 计算数据库中集合的平均值。我想在“计算器”页面的渲染中使用此值,因此它位于“计算器”页面的 post 内。

但是,当我执行model.find({})函数时,函数执行后值没有了,并且不会将修改后的值发送到页面。

我试过将它放在一个函数中并调用它来赋值,但我感觉我可能返回了错误的值。

如果有人知道如何执行此操作,请告诉我。

以下是 JS 文件的代码:

// Calculation POST Handler:
router.post("/calculator", ensureAuthenticated, (req, res) => {
  /*BEGINNING OF CALCULATION METHOD*/
  const ethAddress = req.body.ethereumAddress;
  const KG_CO2_PER_GAS = 0.0001809589427;
  const CO2T_COST = 40; // The cost of Co2 by the Tonne(1000kg) for electricity, found from page 26 of https://www.lse.ac.uk/GranthamInstitute/wp-content/uploads/2019/05/GRI_POLICY-REPORT_How-to-price-carbon-to-reach-net-zero-emissions-in-the-UK.pdf
  var hourlyFlightCo2 = 250; // 250kg Co2 per flight.

  var addressChecked = ethAddress;
  var kilosOfCO2Created = 0;
  var userTransactions = []; // Stores the data retrieved from Etherscan API.
  var totalGasValueForAverage = 0;
  var totalNumofTransactionsForAverage = 0;
  let totalAverageGasValue = 0;
  var totalValue = 0;
  var numOfTransactions = 0;
  var priceOfOffset = 0;
  var userID = req.user._id;
  var flightHours = 0;
  var totalAverageGasValueToDisplay = 0;
  /* PART 1: For getting data, using node-fetch .json to convert the data into an array of objects*/
  fetch(
    `https://api.etherscan.io/api?module=account&action=txlist&address=${ethAddress}&startblock=0&endblock=99999999&sort=asc&apikey=${APIKey}`
  )
    .then((data) => {
      return data.json();
    })
    .then((retrievedData) => {
      // Extract just the results from the Javascript object for a Javascript object of just the transactions.
      userTransactions = retrievedData.result;
      // console.log(userTransactions)
      /* PART 2: Create a loop that takes all gasUsed values from all previous transactions and adds them together for a number to be used in the calculation of emissions. */
      for (const value of userTransactions) {
        // Save transaction to db.
        let dbGasUsed = value.gasUsed;
        let dbEthereumAddress = ethAddress;
        let dbTransactionHash = value.transactionHash;
        // Find all transactions by hash, if they are not already in the database then add them to the database.
        Transaction.findOne({ transactionHash: dbTransactionHash }).then(
          (transaction) => {
            if (transaction) {
              // Check if the user already exists
            } else {
              const newTransaction = new Transaction({
                userID,
                dbGasUsed,
                dbEthereumAddress,
                dbTransactionHash,
              });
              newTransaction.save();
            }
          }
        );
        let currentValue = Number(value.gasUsed); // Calculate the total amount of gas used by the user.
        totalValue = totalValue + currentValue;
        numOfTransactions++;
      }
      // Calculate average of stored transactions gasUsed
      Transaction.find({})
        .then((transactions) => {
          for (const value of transactions) {
            totalNumofTransactionsForAverage++;
            totalGasValueForAverage = (totalGasValueForAverage+value.dbGasUsed);
          }
          // TODO: NEED TO FIGURE OUT HOW TO STORE THIS VARIABLE FOR USE ON PAGE.
          totalAverageGasValueToDisplay = totalGasValueForAverage/totalNumofTransactionsForAverage;
        });
        

      
      /* PART 3: Calculate values that will be useful for the user to see, such as the total number of transactions tracked, the size of their carbon footprint and the cost to offset it.*/
      kilosOfCO2Created = Math.round(totalValue * KG_CO2_PER_GAS);
      priceOfOffset = (kilosOfCO2Created / 1000) * CO2T_COST; // Calculate cost: ((user emissions(kg) / 1000(kg)) * cost by the tonne (£40))
      flightHours = kilosOfCO2Created / hourlyFlightCo2;
      res.render("calculator.ejs", {
        numOfTransactions: numOfTransactions,
        totalValue: totalValue,
        kilosOfCO2Created: kilosOfCO2Created,
        priceOfOffset: priceOfOffset,
        addressChecked: addressChecked,
        flightHours: flightHours,
        totalAverageGasValue: totalAverageGasValue,
        totalAverageGasValueToDisplay: totalAverageGasValueToDisplay
      });
    });
});

我想在渲染中使用的部分是值“totalAverageGasValueToDisplay”,发现在 transaction.find({})

中分配

保存函数是异步的,要使用它你需要像下面这样在它之前插入等待:

 Transaction.findOne({ transactionHash: 
        dbTransactionHash }).then(async 
                 (transaction) => {
                    if (transaction) {
                    // Check if the user already 
                           exists
                    } else {
                      const newTransaction = new 
                      Transaction({
                           userID,
                           dbGasUsed,
                           dbEthereumAddress,
                           dbTransactionHash,
                          });
                     await newTransaction.save();
                     }
              }
    );

Transaction.find({}) 同步执行 after Transaction.findOne({transactionHash: dbTransactionHash}) statements have been issued for all userTransactions, but before他们中的任何一个都完成了。

更一般地说,代码的第 2 部分包含许多异步语句,必须在执行第 3 部分之前完成这些语句。为此,第 3 部分必须在第 2 部分之后的 .then 函数中出现。

/* PART 2: ... */
var findStatements = [];
for (const value of userTransactions) {
  ...
  findStatements.push(
    Transaction.findOne({transactionHash: dbTransactionHash}).then(
      (transaction) => {
        ...
        return newTransaction.save().then(function() {
          let currentValue = Number(value.gasUsed);
          totalValue = totalValue + currentValue;
          numOfTransactions++;
        });
      }
    )
  );
}
Promise.all(findStatements).then(function() {
  // Calculate average of stored transactions gasUsed
  return Transaction.find({}).then(...);
}).then(function() {
  /* PART 3: ... */
  ...
});