在graphql中,组合多个源中的字段共享一个共同值的多个源的最佳方法是啥?

Posted

技术标签:

【中文标题】在graphql中,组合多个源中的字段共享一个共同值的多个源的最佳方法是啥?【英文标题】:In graphql, what is the best way to combine multiple sources where fields in both sources share a common value?在graphql中,组合多个源中的字段共享一个共同值的多个源的最佳方法是什么? 【发布时间】:2021-04-08 12:55:12 【问题描述】:

这里自称graphql-noob。

也就是说,让我们假设 Mongo/Express/React/Node/Gatsby JS 项目中的以下页面级 graphql 查询:

import React from 'react';

import Layout from '../components/Layout';
import  graphql  from 'gatsby';
import  Link  from 'gatsby';
import ItemImg from '../components/ItemImg';

const IndexPage = (props) => 
  const arrayItems = props.data.allMongoDBDomainDataArraySource.edges;

  return (
    <Layout>
      <div id="main">
        <div className="inner">
          <header>
            <h1>
              Site Title
              <br />
            </h1>
            <p>
              Generic site text.
            </p>
          </header>
          <section className="tiles">
            arrayItems.map(item =>
              <article>
                <span className="image">
                  <ItemImg></ItemImg>
                </span>
                <Link to="/Generic">
                  <h2>item.node.propertyToBeUsed1 + ': ' + item.node.propertyToBeUsed2</h2>
                  <div className="content">
                    <p>'Info1: ' + item.node.propertyToBeUsed3</p>
                    <p>'Info2: ' + item.node.propertyToBeUsed4</p>
                  </div>
                </Link>
              </article>,
            )
          </section>
        </div>
      </div>
    </Layout>
  );
;

export default IndexPage;

export const pageQuery = graphql`
query DomainDataArrayAndSourceFilesystemImage
    allMongoDBDomainDataArraySource
      edges 
        node 
          uniqueId
          imgFilename
          metadata
        
      
      
    allFile(
      filter: 
        extension:  regex: "/(jpg)|(png)|(tif)|(tiff)|(webp)|(jpeg)/" 
        absolutePath:  regex: "/assets/images/" 
      
    ) 
      edges 
        node 
          name
          ext
          childImageSharp 
            fluid(maxWidth: 915, quality: 70) 
              aspectRatio
              ...GatsbyImageSharpFluid
            
          
        
      
    
  
`

我希望上面的 sn-p 足以让熟悉底层技术的人熟悉如何尝试使用此查询的上下文(对于它的价值:以上适用于 graphiql) .

从概念上讲,我已经成功地将allMongoDBDomainDatayArraySource 映射为我的index.js 页面上的重复&lt;section&gt; 元素。

现在,任务是:如何将通过gatsby-source-filesystem 解析器加载的图像与&lt;section&gt; 元素中的每个映射项关联起来,如上面的代码段所示(每个映射项包含所需图片的文件名,可从gatsby-source-filesystem获取)。

为清楚起见,allMongoDBDomainDataArraySourceimgFilename 以及 allFileedges.node.nameext 的串联(中间有一个“.”)将等效于 SQL @987654340 @条件类似于我正在尝试做的事情。

我已经尝试尝试向页面查询添加可变参数,但是看到多个源被组合成一个查询并在构建时映射,我真正需要的类似于 JOIN 运算符在SQL做。

我还尝试从index.js 页面分解&lt;Img&gt; Gatsby 元素并创建所谓的模板或组件——这就是ItemImg 元素试图做的事情.

不幸的是,ItemImg 方法最终会失败,因为页面查询与非页面组件不兼容。

在这种情况下,我能够查询 graphql 的唯一方法是使用 StaticQuery(它有效,但不是动态的,因为它使用了硬编码的图像路径)。

但是,至少我的页面最终正确呈现(尽管同一张图像重复了 831 次)。

我确实找到了这个graphql feature request regarding the ability to pass variables to StaticQuery

显然,上述功能请求已在 gatsby-plugin-image beta #27950 中得到解决,尽管在与讨论的链接中有点不清楚,我实施的尝试最终失败了,因为我最终得到了整个“你的组件上的 graphql 查询将不会再次尝试使用非页面组件时加载”错误。

我的目标是最终将文件名(我在allMongoDBDomainDataArraySource 中拥有)作为道具传递给组件,该组件将依次查询图像并返回&lt;Img&gt; 元素。

我知道我的一些尝试可能不适合 graphql 的范式,所以我很好奇是否有人可以帮助我指出解决这个问题的正确概念或方法。

我已经阅读了关于模式拼接的文章,使用 createPages API(我认为这可能是矫枉过正,因为我相信可以按照我试图实现的方式组合查询),并创建您的自己的架构类型(这可能是我需要做的)。

让我知道您认为我应该研究和/或实施什么(即设计模式等)。

【问题讨论】:

【参考方案1】:

createPages API 旨在用于当您需要基于某些字段(slug、URL、路径等)生成动态页面或 URL 时,如您所说,您在主页上过度杀伤了该过程根本不是动态路径,因此这种方法不适合您的用例。

说你有多种方法可以绕过这个当前的限制(正如你所说,仍然在 Gatsby 的实验室中处于测试阶段,但它需要一些时间才能稳定)但这是一个广泛的问题,如果没有工作沙箱很难回答操纵。

在我看来,如果您可以访问原始数据,实现它的最简单方法是操作您的 allMongoDBDomainDataArraySource 以添加与您的图像的某种关系、某种字段名称或类似的东西.这样,一旦您检索到了 allMongoDBDomainDataArraySource,您就可以进行另一个 GraphQL 查询来获取您的图像,并在同一打印 &lt;section&gt; 该字段的循环过滤器中获取匹配的图像。比如:

import  Link  from 'gatsby';
import Img from 'gatsby-image';
import React from 'react';

import Layout from '../components/Layout';

const IndexPage = (props) => 
  const arrayItems = props.data.allMongoDBDomainDataArraySource.edges;
  const allImages = props.data.allFile.edges;

  return (
    <Layout>
      <div id="main">
        <div className="inner">
          <header>
            <h1>
              Site Title
              <br />
            </h1>
            <p>
              Generic site text.
            </p>
          </header>
          <section className="tiles">
            arrayItems.map(item => 
              let matchingImage = allImages.filter(image => image.name === arrayItems.imageName); // here you are getting the proper image

              return <article key=item.node.propertyToBeUsed1>
                <span className="image">
                  <Img fluid=matchingImage.childImageSharp.fluid />
                </span>
                <Link to="/Generic">
                  <h2>item.node.propertyToBeUsed1 + `: ` + item.node.propertyToBeUsed2</h2>
                  <div className="content">
                    <p>`Info1: ` + item.node.propertyToBeUsed3</p>
                    <p>`Info2: ` + item.node.propertyToBeUsed4</p>
                  </div>
                </Link>
              </article>;
            )
          </section>
        </div>
      </div>
    </Layout>
  );
;

export default IndexPage;

export const pageQuery = graphql`
    query DomainDataArrayAndSourceFilesystemImage
        allMongoDBDomainDataArraySource
            edges 
                node 
                    uniqueId
                    imgFilename
                    metadata
                
            
        
        allFile(
            filter: 
                extension:  regex: "/(jpg)|(png)|(tif)|(tiff)|(webp)|(jpeg)/" 
                absolutePath:  regex: "/assets/images/" 
            
        ) 
            edges 
                node 
                    name
                    ext
                    imageName # <--- your filter field
                    childImageSharp 
                        fluid(maxWidth: 915, quality: 70) 
                            aspectRatio
                            ...GatsbyImageSharpFluid
                        
                    
                
            
        
    
`;

代码非常不言自明,您只需注意循环的key 字段。剩下的只是过滤(使用find循环)从allImages获取图像并使用&lt;Img&gt;gatsby-image显示它。

【讨论】:

嗨 Ferran,非常感谢您指出我回到这种方法(我第一次尝试使用 find() 数组方法并且没有完全正确的结构,所以这有帮助很多)!在这之后我又追了一点尾巴,因为我的一些源图像对于 gatsby-image 来说是“不可接受的”,但我认为现在基本上已经解决了。再次感谢!

以上是关于在graphql中,组合多个源中的字段共享一个共同值的多个源的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

Graphql字段中的多个参数

GraphQL 为列表和详细查询共享相同的对象类型

如何在graphql中获取响应中的所有字段而不在查询中传递任何字段名称

如何在 GraphQL 中解析来自多个数据源的字段

GraphQL 不允许查询不同的字段

如果它们共享任何键值对,如何合并来自不同列表的多个字典?