На днях я работал над довольно простым обновлением приложения, которое я создаю на стороне, Track Dat Baby, и у меня возникла проблема, когда я пытался отсортировать список данных из GraphQL по дате. . Оглядываясь назад, это было действительно просто, я просто подходил к этому с неправильного направления.

Если вы не знаете, что такое GraphQL и как выглядят запросы, я бы порекомендовал прочитать Документацию по GraphQL. Я также использую GraphCool, который добавляет несколько очень полезных фильтров и аргументов запроса, которые значительно упрощают работу с данными. Я собираюсь сразу перейти к своему запросу и своему первоначальному способу обработки сортировки.

Во-первых, позвольте мне рассказать вам немного о приложении. Track Dat Baby - это простое приложение для молодых родителей, которое позволяет отслеживать количество кормлений и количество грязных подгузников у их новорожденного ребенка. Это очень важный набор данных для молодых родителей, которые нужно знать, потому что он позволяет им узнать, правильно ли прогрессирует их ребенок на ранних стадиях. Схема GraphQL Track Data Baby бывает трех разных типов: User, Baby и Entry. Что я пытался сделать, так это получить пользователя, у которого есть ребенок, в который были добавлены записи, а затем отсортировать эти записи по дате, когда пользователь их добавил.

Схема типа записи:

type Entry implements Node {
  baby: Baby @relation(name: "BabyOnEntry")
  childType: String!
  createdAt: DateTime!
  id: ID! @isUnique
  parentType: String!
  time: DateTime! @defaultValue(value: "2017-07-30T22:51:45.384")
  updatedAt: DateTime!
}

Хорошо, давайте поработаем над моим первоначальным подходом. Первоначально я запрашивал все записи, связанные с младенцем, с помощью следующего запроса GraphQL.

query {
  user {
    id
    baby {
      id
      entires {
        id
        parentType
        childType
        time
      }
    }
  }
}

Если вы не уверены, что делает этот запрос, сначала мы запрашиваем текущего пользователя, ребенка, связанного с пользователем, а затем записи. Мы хотим получить только поля ID, parentType, childType и time в типе Entry. Мы собираемся сосредоточиться только на поле time.

Хорошо, давайте перейдем к перечислению записей и их сортировке. Я использую React для создания приложения, поэтому я легко смог получить список записей и отобразить их с помощью React Apollo.

import React from "react";
import { gql, graphql } from "react-apollo";
const EntriesList = props => {
  if (props.data.loading) {
    return (
      <p>{props.data.error.message}</p>
    );
  }
  
  const entries = props.data.user.baby.entries;
  return (
    <ul>
      {entries.map((entry, key) =>
        <li>{entry.time}</li>
      }
    </ul>
  );
}
export const entriesListQuery = gql`
  query entries {
    user {
      id
      baby {
        id
        entries {
          id
          parentType
          childType
          time
        }
      }
    }
  }
`;
const EntriesListWithData = graphql(entriesListQuery)(EntriesList);
export default EntriesListWithData;

Теперь у нас есть EntriesListWithData компонент, который выводит ul список со всеми записями, перечисленными в порядке по умолчанию, в котором они были созданы, а самые новые добавляются в конец списка. Я хотел бы видеть записи, перечисленные в их поле time, которое задает пользователь, и самые новые, добавленные в начало списка.

Моя первая мысль была: «Эй, в Javascript есть .sort, может, мне стоит попробовать». Я уверен, что вы, возможно, уже знаете, в чем проблема, но позвольте мне продолжить, потому что это поставило меня в тупик, и я уверен, что это может поставить в тупик некоторых других людей, плохо знакомых с GraphQL. С помощью Javascript .sort я подумал, что могу взять массив entries и отсортировать их, прежде чем передать их в .map вот так.

{entries
  .sort((a,b) => a.time - b.time )
  .map(entry => <li>{time}</li> );
}

Попытка запустить это всегда возвращала конкретную ошибку, которую мне было трудно отследить. Код просто потерпит неудачу и не предоставит мне больше информации об этом.

TypeError: Cannot assign to read only property '1' of object '[object Array]'

Я продолжал пробегать и гуглить варианты, пытаясь понять, что происходит. Наконец, что-то щелкнуло, и я понял, что GraphQL имеет свои собственные возможности сортировки и что ошибка, с которой я столкнулся, была связана с тем, что массив GraphQL был доступен только для чтения, что приводило к появлению ошибки в .sort.

Исправить это очень просто. Речь идет о внесении очень небольшого изменения в запрос GraphQL.

query entries {
  user {
    id 
    baby {
      id
      entries(
        orderBy: time_ASC
      ) {
        id
        parentType
        childType
        time
      }
    }
  }
}

Если вы посмотрите, то заметите, что я добавил только orderBy: time_ASC. При этом все записи упорядочены по полю времени и отсортированы по возрастанию. Это было так просто. Я бы рекомендовал прочитать документацию по GraphCool, поскольку это относится к их API.

Хотя я потратил больше времени, чем следовало бы, пытаясь понять это, я был взволнован, обнаружив, что GraphCool сделал это так легко. Еще одна причина, по которой мне нравится использовать GraphCool + GraphQL.

Я надеюсь, что это поможет кому-то еще, кто, возможно, пытается изучить GraphQL и нуждается в помощи в поиске некоторых таких мелких функций.