首页 > 解决方案 > 我从 Graphql 游乐场和前端得到不同的结果

问题描述

我正在使用 graphql 和 Vue.js 和 apollo

这是我的日期银行

const sensorsdb = [
{
    name: "sensor 1",
    id: "s-1",
    timestamp: 1582021371,
    value: 100
},
{
    name: "sensor 1",
    id: "s-1",
    timestamp: 1579451703,
    value: 150
},
{
    name: "sensor 2-1",
    id: "s-2-1",
    timestamp: 1582021371,
    value: 200
},
{
    name: "sensor 2-2",
    id: "s-2-2",
    timestamp: 1579451703,
    value: 350
},
{
    name: "sensor 2-2",
    id: "s-2-2",
    timestamp: 1582021371,
    value: 300
},
{
    name: "sensor 3",
    id: "s-3",
    timestamp: 1582021371,
    value: 400
},];

我想根据对象 id 获取所有对象。sensorId 是一个数组。因为我想获得具有多个 id 的多个对象。

以下是我获取对象的 API 函数。

  async getDataById({ sensorId }) {
    let sensorsData = [];
    for (let i = 0; i < sensorId.length; i++) {
        let sensorData = this.sensorDataStore.sensors.filter(sensor => sensor.id === sensorId[i]);
        sensorsData = sensorsData.concat(sensorData);
    }
    return sensorsData;
}

在前端,gql 文件如下:

query sensorData($id: [String]){
sensorData(id: $id){
    name
    id
    value
    timestamp
}}

在 vue.js 中使用我的 apollo 查询代码,在这种情况下 selectedSensorId 是 ["s-2-1", "s-2-2"]

<ApolloQuery :query="require('../graphql/sensorDataById.gql')" :variables="{ id: selectedSensorId }">
  <template v-slot="{ result: { loading, error, data } }">
    <b-loading :is-full-page=true :active.sync=loading :can-cancel="false"/>
    <div v-if="error">
      <no-data-error />
    </div>
    <div v-if="data">
      {{ data }}
      <bar-chart-view :sensorInfo="data.sensorData"/>
    </div>
  </template>
</ApolloQuery>

但是我得到了以下不同的结果:具有正确结果的 Graphql Playground The front-end result with duplicated sensor-s-2 具有正确结果的 Graphql 操场

带有重复 sensor-s-2 的前端结果

标签: vue.jsgraphqlapollo

解决方案


Apollo 客户端根据文档中描述的id和字段对结果进行规范化。如果一个数组返回多个相同的项,默认情况下它们将共享相同的缓存键,这意味着客户端返回的将是同一个对象。__typenameid

您应该为dataIdFromObject您的构造函数提供一个自定义函数,以InMemoryCache适应您的特定用例。就像是:

const dataIdFromObject = object => {
  switch (object.__typename) {
    case 'SensorDataPoint': return `SensorDataPoint:${object.id}:{value}`;
    default: return defaultDataIdFromObject(object);
  }
}

请注意,如果您在其他地方使用相同的类型,您可能会在突变后正确更新缓存时遇到问题,因为我们现在同时关闭valueid。您可能需要考虑一种不同的方法来处理您的模式,其中 id 实际上是唯一的:

type SensorDataPoint {
  id: ID!
  sensorId: ID!
  sensorName: String!
  value: Int!
  timestamp: Int!
}

甚至更好

type SensorDataPoint {
  id: ID!
  value: Int!
  timestamp: Int!
  sensor: Sensor!
}

type Sensor {
  id: ID!
  name: String!
}

推荐阅读