简体   繁体   English

我的特快电话出了什么问题? 我需要一个 ID 数组,但它返回一个空数组

[英]What is going wrong with my express call? I need an array of ID's but its returning an empty array

Im guessing this problem is because I don't know how to use async await effectively.我猜这个问题是因为我不知道如何有效地使用异步等待。 I still dont get it and I've been trying to understand for ages.我仍然不明白,我多年来一直在努力理解。 sigh.叹。

Anyway, heres my function:无论如何,这是我的 function:

app.post("/declineTrades", async (request, response) => {
  //---------------------------------------------
  const batch = db.batch();
  const listingID = request.body.listingID;
  const tradeOfferQuery = db
    //---------------------------------------------
    //Get trade offers that contain the item that just sold
    //(therefore it cannot be traded anymore, I need to cancel all existing trade offers that contain the item because this item isn't available anymore)
    //---------------------------------------------
    .collection("tradeOffers")
    .where("status", "==", "pending")
    .where("itemIds", "array-contains", listingID);
  //---------------------------------------------
  //Function that gets all trade offers that contain the ID of the item.
  async function getIdsToDecline() {
    let tempArray = [];
    tradeOfferQuery.get().then((querySnapshot) => {
      querySnapshot.forEach((doc) => {
        //For each trade offer found
        let offerRef = db.collection("tradeOffers").doc(doc.id);
        //Change the status to declined
        batch.update(offerRef, { status: "declined" });
        //Get the data from the trade offer because I want to send an email 
        //to the  who just got their trade offer declined.
        const offerGet = offerRef.get().then((offer) => {
          const offerData = offer.data();
          //Check the items that the receiving person had in this trade offer
          const receiverItemIds = Array.from(
            offerData.receiversItems
              .reduce((set, { itemID }) => set.add(itemID), new Set())
              .values()
          );
          //if the receiver item id's array includes this item that just sold, I know that
          //I can get the sender ID (users can be sender or receiver, so i need to check which person is which)
          if (receiverItemIds.includes(listingID)) {
            tempArray.push(offerData.senderID);
          }
        });
      });
    });
    //With the ID's now pushed, return the tempArray
    return tempArray;
  }
  //---------------------------------------------
  //Call the above function to get the ID's of people that got declined 
  //due to the item no longer being available
  const peopleToDeclineArray = await getIdsToDecline();
  //Update the trade offer objects to declined
  const result = await batch.commit();
  //END
  response.status(201).send({
    success: true,
    result: result,
    idArray: peopleToDeclineArray,
  });
});

Im guessing that my return tempArray is in the wrong place?我猜我的return tempArray是在错误的地方? But I have tried putting it in other places and it still returns an empty array.但我试过把它放在其他地方,它仍然返回一个空数组。 Is my logic correct here?我的逻辑在这里正确吗? I need to run the forEach loop and add to the array before the batch.commit happens and before the response is sent.我需要在batch.commit发生之前和发送响应之前运行 forEach 循环并添加到数组中。

TIA Guys! TIA 伙计们!

As @jabaa pointed out in their comment , there are problems with an incorrectly chained Promise in your getIdsToDecline function.正如@jabaa他们的评论中指出的那样,在您的getIdsToDecline function 中存在错误链接的Promise问题。

Currently the function initializes an array called tempArray , starts executing the trade offer query and then returns the array (which is currently still empty) because the query hasn't finished yet.目前 function 初始化一个名为tempArray的数组,开始执行交易报价查询,然后返回该数组(目前仍为空),因为查询尚未完成。

While you could throw in await before tradeOfferQuery.get() , this won't solve your problem as it will only wait for the tradeOfferQuery to execute and the batch to be filled with entries, while still not waiting for any of the offerRef.get() calls to be completed to fill the tempArray .虽然您可以在tradeOfferQuery.get()之前加入await ,但这并不能解决您的问题,因为它只会等待tradeOfferQuery执行和批次填充条目,同时仍不等待任何offerRef.get()调用完成以填充tempArray

To fix this, we need to make sure that all of the offerRef.get() calls finish first.为了解决这个问题,我们需要确保所有的offerRef.get()调用首先完成。 To get all of these documents, you would use the following code to fetch each document, wait for all of them to complete and then pull out the snapshots:要获取所有这些文档,您将使用以下代码获取每个文档,等待所有文档完成,然后提取快照:

const itemsToFetch = [ /* ... */ ];
const getAllItemsPromise = Promise.all(
  itemsToFetch.map(item => item.get())
);

const fetchedItemSnapshots = await getAllItemsPromise;

For documents based on a query, you'd tweak this to be:对于基于查询的文档,您可以将其调整为:

const querySnapshot = /* ... */;

const getSenderDocPromises = [];
querySnapshot.forEach((doc) => {
  const senderID = doc.get("senderID");
  const senderRef = db.collection("users").doc(senderID);

  getSenderDocPromises.push(senderRef.get());
}

const getAllSenderDocPromise = Promise.all(getSenderDocPromises);

const fetchedSenderDataSnapshots = await getAllSenderDocPromise;

However neither of these approaches are necessary, as the document you are requesting using these offerRef.get() calls are already returned in your query so we don't even need to use get() here!但是,这些方法都不是必需的,因为您使用这些offerRef.get()调用请求的文档已经在您的查询中返回,因此我们甚至不需要在这里使用get()

(doc) => {
  let offerRef = db.collection("tradeOffers").doc(doc.id);
  //Change the status to declined
  batch.update(offerRef, { status: "declined" });
  //Get the data from the trade offer because I want to send an email 
  //to the  who just got their trade offer declined.
  const offerGet = offerRef.get().then((offer) => {
    const offerData = offer.data();
    //Check the items that the receiving person had in this trade offer
    const receiverItemIds = Array.from(
      offerData.receiversItems
        .reduce((set, { itemID }) => set.add(itemID), new Set())
        .values()
    );
    //if the receiver item id's array includes this item that just sold, I know that
    //I can get the sender ID (users can be sender or receiver, so i need to check which person is which)
    if (receiverItemIds.includes(listingID)) {
      tempArray.push(offerData.senderID);
    }
  });
}

could be replaced with just可以替换为

(doc) => {
  // Change the status to declined
  batch.update(doc.ref, { status: "declined" });

  // Fetch the IDs of items that the receiving person had in this trade offer
  const receiverItemIds = Array.from(
    doc.get("receiversItems") // <-- this is the efficient form of doc.data().receiversItems
      .reduce((set, { itemID }) => set.add(itemID), new Set())
      .values()
  );

  // If the received item IDs includes the listed item, add the
  // sender's ID to the array
  if (receiverItemIds.includes(listingID)) {
    tempArray.push(doc.get("senderID"));
  }
}

which could be simplified to just这可以简化为

(doc) => {
  //Change the status to declined
  batch.update(doc.ref, { status: "declined" });

  // Check if any items that the receiving person had in this trade offer
  // include the listing ID.
  const receiversItemsHasListingID = doc.get("receiversItems")
    .some(item => item.itemID === listingID);

  // If the listing ID was found, add the sender's ID to the array
  if (receiversItemsHasListingID) {
    tempArray.push(doc.get("senderID"));
  }
}

Based on this, getIdsToDecline actually queues declining the invalid trades and returns the IDs of those senders affected.基于此, getIdsToDecline实际上将拒绝无效交易排队并返回受影响的发件人的 ID。 Instead of using the batch and tradeOfferQuery objects that are outside of the function that make this even more unclear, you should roll them into the function and pull it out of the express handler.不要使用 function 之外的batchtradeOfferQuery对象,这会使这变得更加不清楚,您应该将它们滚动到 function 中并将其拉出快速处理程序。 I'll also rename it to declineInvalidTradesAndReturnAffectedSenders .我还将把它重命名为declineInvalidTradesAndReturnAffectedSenders

async function declineInvalidTradesAndReturnAffectedSenders(listingID) {
  const tradeOfferQuery = db
    .collection("tradeOffers")
    .where("status", "==", "pending")
    .where("itemIds", "array-contains", listingID);

  const batch = db.batch();
  const affectedSenderIDs = [];
  
  const querySnapshot = await tradeOfferQuery.get();

  querySnapshot.forEach((offerDoc) => {
    batch.update(offerDoc.ref, { status: "declined" });

    const receiversItemsHasListingID = offerDoc.get("receiversItems")
      .some(item => item.itemID === listingID);

    if (receiversItemsHasListingID) {
      affectedSenderIDs.push(offerDoc.get("senderID"));
    }
  }

  await batch.commit(); // generally, the return value of this isn't useful

  return affectedSenderIDs;
}

This then would change your route handler to:然后,这会将您的路由处理程序更改为:

app.post("/declineTrades", async (request, response) => {
  
  const listingID = request.body.listingID;
  
  const peopleToDeclineArray = await declineInvalidTradesAndReturnAffectedSenders(listingID);

  response.status(201).send({
    success: true,
    result: result,
    idArray: peopleToDeclineArray,
  });
});

Then adding the appropriate error handling, swapping out the incorrect use of HTTP 201 Created for HTTP 200 OK , and using json() instead of send() ;然后添加适当的错误处理, HTTP 201 Created for HTTP 200 OK的错误使用,并使用json()而不是send() you now get:你现在得到:

app.post("/declineTrades", async (request, response) => {
  try {
    const listingID = request.body.listingID;
  
    const affectedSenderIDs = await declineInvalidTradesAndReturnAffectedSenders(listingID);

    response.status(200).json({
      success: true,
      idArray: affectedSenderIDs, // consider renaming to affectedSenderIDs
    });
  } catch (error) {
    console.error(`Failed to decline invalid trades for listing ${listingID}`, error);

    if (!response.headersSent) {
      response.status(500).json({
        success: false,
        errorCode: error.code || "unknown"
      });
    } else {
      response.end(); // forcefully end corrupt response
    }
  }
});

Note: Even after all these changes, you are still missing any form of authentication.注意:即使进行了所有这些更改,您仍然缺少任何形式的身份验证。 Consider swapping the HTTPS Event Function out for a Callable Function where this is handled for you but requires using a Firebase Client SDK. Consider swapping the HTTPS Event Function out for a Callable Function where this is handled for you but requires using a Firebase Client SDK.

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM