首页 > 解决方案 > 使用 Javascript 中的 Fetch 在 JSON 中搜索值

问题描述

我正在 VS Code 中使用用于客户数据的 html 表单制作应用程序。由于我们公司的设置,我必须将数据存储在 Google 表格中。经过大量搜索后,我在 YouTube 上找到了一系列很棒的教程,向我展示了如何通过将数据发布为应用程序脚本 Web 应用程序来访问 JSON 格式的数据,然后使用 fetch 获取数据。

但是,我对所有这一切都非常陌生,而我没有学到的一件事,并且在试图找到(即使在这个网站上)时遇到了很多麻烦,就是如何搜索数据以查看是否值已存在于谷歌表中。我不想在工作表中创建重复的客户。我希望有人可以告诉我如何通过 fetch 搜索 JSON 数据,以在变量或更好的方法中获取 true 或 false,对于单个键值以及一组对(多个键对)。例如,假设我正在尝试使电话 # 成为唯一键,并且我希望能够搜索那个或带有姓氏的电话 #。然后,如果值已经存在,或者它/它们不存在,我可以继续创建适当的行为。

这是我的 HTML 的样子:

<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-eOJMYsd53ii+scO/bJGFsiCZc+5NDVN2yr8+0RDqr0Ql0h+rP48ckxlpbzKgwra6" crossorigin="anonymous">

    <title>Add a Customer</title>
  </head>
  <body>
    <div class="container">
      <h1>Add a Customer</h1>
      <form id="customerForm" novalidate>
          <div class="row p-2">
              <div class="col">
                <input type="text" class="form-control" placeholder="First name" aria-label="First name" id="firstName" required minlength="2">
                <div id="validationServer05Feedback" class="invalid-feedback">
                  Please provide a valid First Name.
                </div>            
              </div>
              <div class="col">
                <input type="text" class="form-control" placeholder="Last name" aria-label="Last name" id="lastName" required minlength="3">
                <div id="validationServer05Feedback" class="invalid-feedback">
                  Please provide a valid Last Name.
                </div>            
              </div>
            </div>
            <div class="row p-2">
              <div class="col">
                <input type="text" class="form-control" placeholder="Telephone" aria-label="Telephone" id="telephone">
              </div>
              <div class="col">
                <input type="text" class="form-control" placeholder="City" aria-label="City" id="city">
              </div>
            </div>
            <div class="col-12">
              <button type="submit" class="btn btn-primary" type="button" id="submitButton">
                <span id="buttonSpinner" class="spinner-border spinner-border-sm d-none" role="status" aria-hidden="true"></span>
                <span id="buttonText">Send</span>
              </button>
              <div class="alert alert-danger mt-2 d-none" role="alert" id="unknownError">
                Something Went Horribly Wrong!
              </div>
            </div>
      </form>
    </div>

    <!-- Optional JavaScript; choose one of the two! -->

    <!-- Option 1: Bootstrap Bundle with Popper -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.bundle.min.js" integrity="sha384-JEW9xMcG8R+pH31jmWH6WWP0WintQrMb4s7ZOdauHnUtxwoG2vI5DkLtS3qm9Ekf" crossorigin="anonymous"></script>

    <!-- Option 2: Separate Popper and Bootstrap JS -->
    <!--
    <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.9.1/dist/umd/popper.min.js" integrity="sha384-SR1sx49pcuLnqZUnnPwx6FCym0wLsk5JZuNx2bPPENzswTNFaQU1RDvt3wT4gWFG" crossorigin="anonymous"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta3/dist/js/bootstrap.min.js" integrity="sha384-j0CNLUeiqtyaRmlzUHCPZ+Gy5fQu0dQ6eZ/xAww941Ai1SxSY+0EQqNXNE6DZiVc" crossorigin="anonymous"></script>
    -->
    <script src="customers.js"></script>
  </body>
</html>

和客户端 JavaScript:

var customerForm = document.getElementById("customerForm");
var firstName = document.getElementById("firstName");
var lastName = document.getElementById("lastName");
var telephone = document.getElementById("telephone");
var city = document.getElementById("city");
var submitButton = document.getElementById("submitButton");
var buttonSpinner = document.getElementById("buttonSpinner");
var buttonText = document.getElementById("buttonText");
var unknownError = document.getElementById("unknownError");


function afterSubmit(e){

    e.preventDefault();

    if (customerForm.checkValidity() === false) {
        e.stopPropagation();
        for(field of customerForm.elements) {
            if(!field.checkValidity()){
                field.classList.add("is-invalid");
            }
        }
        return;
      }
    //   customerForm.classList.add('was-validated')
    for(field of customerForm.elements) {
        field.classList.remove("is-invalid");
    }

    var info = {
        first: firstName.value,
        last: lastName.value,
        telephone: telephone.value,
        city: city.value,
    };

    var url = "https://script.google.com/macros/s/AKfycbyWBN9OE7USFtzweft6V7XvS2nD8fDsyuCDb0pN_jGApUFr_UUsXBG1SQ-oU0OT8Ep6/exec";

    buttonText.textContent = "Sending...";
    buttonSpinner.classList.remove("d-none");
    submitButton.disabled = true;

    fetch(url,{
        method: 'POST',
        cache: 'no-cache',
        redirect: 'follow',
        body: JSON.stringify(info)
    })
    .then(res => res.json())
    .then(res => {
        console.log(res);
        customerForm.reset();
        buttonText.textContent = "Send";
        buttonSpinner.classList.add("d-none");
        submitButton.disabled = false;
    })
    .catch(err => {
        console.log(err);
        console.log("Something went wrong");
        unknownError.classList.remove("d-none");
        setTimeout(function(){
            unknownError.classList.add("d-none");
            buttonText.textContent = "Send";
            buttonSpinner.classList.add("d-none");
            submitButton.disabled = false;
        },3000);
    });
}

customerForm.addEventListener("submit",afterSubmit);

和 Apps 脚本 JavaScript:

function doGet(e) {
    const limit = e.parameter.limit === "undefined" ? null : e.parameter.limit;
    const limitNumber = /^[1-9]\d*$/.test(limit) ? parseInt(limit) : null;
    const offset = e.parameter.offset === "undefined" ? null : e.parameter.offset;
    const offsetNumber = /^[1-9]\d*$/.test(offset) ? parseInt(offset) : null;  
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const ws = ss.getSheetByName("customers");
    let data = ws.getRange("A1").getDataRegion().getValues();
    const headers = data.shift();  
    const jsonArray = data.map(r => {
      let obj = {};
      headers.forEach((h,i) => {
        obj[h] = r[i];
      });
      return obj;
    });
  
    const response = [{status: 200,data: jsonArray}];  
    return sendJSON_(response);    
  }

function doPost(e){  
    const requiredColumns = ["first","last"];
    let jsonResponse;  
    const ss = SpreadsheetApp.getActiveSpreadsheet();
    const ws = ss.getSheetByName("customers");  
    const headers = ws.getRange(1,1,1,ws.getLastColumn()).getValues()[0];
    const headersOriginalOrder = headers.slice();
    headersOriginalOrder.shift();
    headers.shift();
    headers.sort();  
    const body = e.postData.contents;
    const bodyJSON = JSON.parse(body);
    const headersPassed = Object.keys(bodyJSON).sort();
  
    if(!checkColumnsPassed_(headers,headersPassed,requiredColumns)){
      throw new Error("Something went wrong");
      return;
    }
  
    const arrayofData = headersOriginalOrder.map(h => bodyJSON[h]);  
    const aoaIds = ws.getRange(2,1,ws.getLastRow()-1,1).getValues();
    const newIDNumber = getMaxFromArrayOfArray_(aoaIds) +1;
    arrayofData.unshift(newIDNumber);
    ws.appendRow(arrayofData);
    bodyJSON.id = newIDNumber;
    return sendJSON_(bodyJSON);
  }

function checkColumnsPassed_(arrAllColumns,arrColumnsPassed,arrRequiredColumns){
    if(!arrRequiredColumns.every(item => arrColumnsPassed.includes(item))) return false;
    if(!arrColumnsPassed.every(item => arrAllColumns.includes(item))) return false;
    return true;
  }
  
  function sendJSON_(jsonResponse){
    return ContentService
      .createTextOutput(JSON.stringify(jsonResponse))
      .setMimeType(ContentService.MimeType.JSON);
  }
  
  //return the highest number / id
  function getMaxFromArrayOfArray_(aoa){
    let maxID = 0; 
    aoa.forEach(r => {
      if(r[0] > maxID) maxID = r[0];
    });
    return maxID;
  }

抱歉,如果代码太多,但我想提供我正在使用的所有东西,以防我需要注意一些事情。如果我需要澄清我的问题,请告诉我。

提前感谢您提供的任何帮助!

标签: javascriptjsongoogle-apps-scriptgoogle-sheetsfetch

解决方案


我相信你的目标如下。

  • 提交 HTML 表单时,您要检查输入的电话号码和姓氏是否存在于电子表格的“客户”表中。
  • 当电子表格的“客户”表中不存在输入的电话号码和姓氏时,您要添加它。
  • 当输入的电话号码和姓氏存在于电子表格的“客户”表中时,您不想添加它。

在这种情况下,如何修改doPost您的 Google Apps Script 的功能如下?

从:

if(!checkColumnsPassed_(headers,headersPassed,requiredColumns)){
  throw new Error("Something went wrong");
  return;
}

const arrayofData = headersOriginalOrder.map(h => bodyJSON[h]);

至:

if (!checkColumnsPassed_(headers, headersPassed, requiredColumns)) {
  throw new Error("Something went wrong");
  return;
}

// --- I added below script.
const checkHeaders = ["telephone", "last"];
const [, ...v] = ws.getDataRange().getValues();
const headerObj = headers.reduce((o, f, i) => Object.assign(o, {[f]: i}), {});
const duplicateCheck = v.some(r => checkHeaders.every(h => r[headerObj[h]] == bodyJSON[h]));
if (duplicateCheck) return sendJSON_({duplicated: true});
// ---

const arrayofData = headersOriginalOrder.map(h => bodyJSON[h]);
  • 通过上述修改,当“客户”表中存在telephone和的值时,返回,输入的值不相加,返回。lastduplicateChecktrue{duplicated: true}
  • 另一方面,当 和 的值telephonelast“客户”表中不存在时,duplicateCheck返回false并添加输入的值。

笔记:

参考:


推荐阅读