【问题标题】:How to query a firestore search for a name within a document?如何在文档中查询 Firestore 搜索名称?
【发布时间】:2021-04-22 03:17:41
【问题描述】:

我为我的 firestore 数据库设置的是一个名为“funkoPops”的集合。其中包含 funkoPops 类型的文档,以及包含该类型所有流行音乐的 funkoData 数组。如下图所示


我还应该注意,funkoPops 集合有数百个“流派”文档,这基本上是 funko pop 系列以及我在网上抓取的 funkoData 的子集合,现在需要能够通过数组字段进行搜索'funkoData' 将名称字段与给定的搜索参数匹配。

collection: funkoPops => document: 2014 Funko Pop Marvel Thor Series => fields: funkoData: [ 
{
  image: "string to hold image",
  name: "Loki - with helmet",
  number: "36"
},
{
  image: "string to hold image",
  name: "Black and White Loki with Helmet - hot topic exsclusive",
  number: "36"
},
{
etc...
}

那么我如何在 firestore 中运行查询以便能够在集合中搜索('funkoPops'),在文档字段中搜索名称。

我有能力像这样搜索流派,这会返回流派和带有以下数据数组的文档:

const getFunkoPopGenre = async (req, res, next) => {
  try {
    console.log(req.params);
    const genre = req.params.genre;
    const funkoPop = await firestore.collection("funkoPops").doc(genre);
    const data = await funkoPop.get();
    if (!data.exists) {
      res.status(404).send("No Funko Pop found with that search parameter");
    } else {
      res.send(data.data());
    }
  } catch (error) {
    res.status(400).send(error.message);
  }
};

我试图通过字段名称搜索的内容如下,并返回一个空的 obj:

const getFunkoPopName = async (req, res, next) => {
  try {
    const name = req.params.name;
    console.log({ name });
    const funkoPop = await firestore
      .collection("funkoPops")
      .whereEqualTo("genre", name);
    const data = await funkoPop.get();
    console.log(data);
    res.send(data.data());
  } catch (error) {
    res.status(400).send(error);
  }
};

任何帮助都会很棒,谢谢!

【问题讨论】:

  • 希望,字段name的比较条件,所以条件应该是.whereEqualTo('name', name)。同样在firestore中,您必须传递完整的字符串值以进行匹配并获取文档。

标签: javascript database api search google-cloud-firestore


【解决方案1】:

所以我回答这个问题的方式似乎从顶级评论和对 firebase 的更多研究来看,你是否必须匹配一个完整的字符串才能使用 firebase 查询进行搜索。相反,我查询集合中的所有文档,将其添加到数组中,然后 forEach() 每个 funkoData。然后我从那里创建一个 matchArray 并通过我从第一个查询中获得的新 funkoData 数组去 forEach() 。然后在那个 forEach() 里面我有一个新变量 match 是数据数组的过滤器,将数据字段名称与 .inlcudes(search param) 匹配,然后将所有匹配项推送到 matchArr 和 res.send(匹配Arr)。适用于部分字符串以及 .includes() 匹配完整和子字符串。不确定这是否是最好和最有效的方法,但我能够在 1-2 秒内查询大约 20k 数据并找到所有匹配项。代码如下所示

try {
    const query = req.params.name.trim().toLowerCase();
    console.log({ query });
    const funkoPops = await firestore.collection("test");
    const data = await funkoPops.get();
    const funkoArray = [];
    if (data.empty) {
      res.status(404).send("No Funko Pop records found");
    } else {
      data.forEach((doc) => {
        const funkoObj = new FunkoPop(doc.data().genre, doc.data().funkoData);
        funkoArray.push(funkoObj);
      });
      const matchArr = [];
      funkoArray.forEach((funko) => {
        const genre = funko.genre;
        const funkoData = funko.funkoData;
        const matches = funkoData.filter((data) =>
          data.name.toLowerCase().includes(query)
        );
        if (Object.keys(matches).length > 0) {
          matchArr.push({
            matches,
            genre,
          });
        }
      });
      if (matchArr.length === 0) {
        res.status(404).send(`No Funko Pops found for search: ${query}`);
      } else {
        res.send(matchArr);
      }
    }
  } catch (error) {
    res.status(400).send(error.message);
  }

稍作调整,我就可以搜索数据库中的任何字段,并将其与完整字符串和子字符串匹配。

更新

最终只是将类型、名称和数字搜索组合到一个函数中,这样当有人搜索时,查询参数会同时用于所有 3 个搜索,并将所有 3 个搜索的数据作为对象返回,以便我们可以在前端做任何我们喜欢的事情:

const getFunkoPopQuery = async (req, res) => {
  try {
    console.log(req.params);
    const query = req.params.query.trim().toLowerCase();
    const funkoPops = await firestore.collection("test");
    const data = await funkoPops.get();
    const funkoArr = [];
    if (data.empty) {
      res.status(404).send("No Funko Pop records exsist");
    } else {
      data.forEach((doc) => {
        const funkoObj = new FunkoPop(doc.data().genre, doc.data().funkoData);
        funkoArr.push(funkoObj);
      });

      // genre matching if query is not a number
      let genreMatches = [];
      if (isNaN(query)) {
        genreMatches = funkoArr.filter((funko) =>
          funko.genre.toLowerCase().includes(query)
        );
      }
      if (genreMatches.length === 0) {
        genreMatches = `No funko pop genres with search: ${query}`;
      }

      // name & number matching
      const objToSearch = {
        notNullNameArr: [],
        notNullNumbArr: [],
        nameMatches: [],
        numbMatches: [],
      };

      funkoArr.forEach((funko) => {
        const genre = funko.genre;
        if (funko.funkoData) {
          const funkoDataArr = funko.funkoData;
          funkoDataArr.forEach((data) => {
            if (data.name) {
              objToSearch.notNullNameArr.push({
                funkoData: [data],
                genre: genre,
              });
            }
            if (data.number) {
              objToSearch.notNullNumbArr.push({
                funkoData: [data],
                genre: genre,
              });
            }
          });
        }
      });
      // find name that includes query
      objToSearch.notNullNameArr.forEach((funko) => {
        const genre = funko.genre;
        const name = funko.funkoData.filter((data) =>
          data.name.toLowerCase().includes(query)
        );
        if (Object.keys(name).length > 0) {
          objToSearch.nameMatches.push({
            genre,
            name,
          });
        }
      });
      // find number that matches query
      objToSearch.notNullNumbArr.forEach((funko) => {
        const genre = funko.genre;
        const number = funko.funkoData.filter((data) => data.number === query);
        if (Object.keys(number).length > 0) {
          objToSearch.numbMatches.push({
            genre,
            number,
          });
        }
      });

      if (objToSearch.nameMatches.length === 0) {
        objToSearch.nameMatches = `No funko pops found with search name: ${query}`;
      }
      if (objToSearch.numbMatches.length === 0) {
        objToSearch.numbMatches = `No funko pop numbers found with search: ${query}`;
      }

      const searchFinds = {
        genre: genreMatches,
        name: objToSearch.nameMatches,
        number: objToSearch.numbMatches,
      };

      res.send(searchFinds);
    }
  } catch (error) {
    res.status(400).send(error.message);
  }
};

如果有人非常适合后端并且对 Firestore 查询有更多了解,请告诉我!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-25
    • 2020-07-08
    • 2018-04-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多