GROQ 튜토리얼 (How Queries Work)

hwisaac·2023년 6월 15일
0

sanity

목록 보기
1/1

https://www.sanity.io/docs/how-queries-work#8ca3cefc3a31

GROQ 튜토리얼 (How Queries Work)

GROQ (Graph-Relational Object Queries) 쿼리 언어의 아이디어는 애플리케이션이 필요로 하는 정확한 정보를 설명하고, 여러 문서 집합에서 정보를 결합하여 필요한 정확한 필드만 포함된 응답을 생성할 수 있는 것입니다.

프론트엔드에서 이러한 쿼리를 수행하기 위해 클라이언트를 설정하는 데 도움이 필요하다면, JavaScript 또는 PHP용 클라이언트 문서를 확인해보세요. 또한 GROQ Arcade를 방문하여 JSON 소스를 쿼리하고 이 언어에 익숙해질 수도 있습니다.

소개

기본 사항부터 시작해봅시다. 이 간단한 쿼리를 살펴보고 세부 사항을 분석해보겠습니다:

*[_type == 'movie' && releaseYear >= 1979]

일반적으로 쿼리는 *로 시작합니다. 이 별표는 데이터셋의 모든 문서를 나타냅니다. 유용한 작업을 수행하기 위해 일반적으로 이어서 대괄호 내의 필터가 옵니다. 위의 필터는 두 개의 조건으로 구성되어 있습니다:

필터

첫 번째로 문서 유형으로 필터링합니다. Sanity의 모든 문서는 유형을 가져야 하며, 유형은 항상 _type 필드에 있습니다. (Sanity에서는 Sanity 고유의 필드를 필드 이름과 충돌하지 않도록 _로 접두사를 붙입니다.) 따라서 _type == 'movie'는 이 쿼리를 'movie' 유형의 문서로 제한합니다. &&는 "그리고" 연산자입니다.

두 번째 조건인 releaseYear >= 1979는 영화에 releaseYear라는 숫자를 포함한다고 가정합니다. 이 숫자가 1979보다 크거나 같은 문서와 일치합니다.

프로젝션

따라서 이 쿼리를 실행하면 데이터셋에서 1979년 이후의 모든 영화를 포함하는 배열이 결과로 반환됩니다. 멋지군요! 그러나 일반적인 애플리케이션에서 영화는 배우, 스태프, 포스터, 태그 라인, 상영 시간, 평점 등 많은 정보를 포함하는 거대한 문서일 수 있습니다. 개요에서 영화 목록을 렌더링하는 것이 목표라면 대역폭을 낭비하게 됩니다. 이때 프로젝션을 사용할 수 있습니다.

일반적인 프로젝션은 중괄호로 둘러싸여 각 영화에 대해 표시하려는 데이터를 설명합니다. 이 쿼리에서 _id, titlereleaseYear를 사용하여 각 영화에 대한 식별자, 제목 및 출시 연도를 얻는 간단하고 명확한 프로젝션을 작성할 수 있습니다. 다음과 같을 수 있습니다: {_id, title, releaseYear}. 모두 함께 사용하면 다음과 같습니다:

*[_type == 'movie' && releaseYear >= 1979]{ _id, title, releaseYear }

기본 정렬

이제 다른 문제가 있습니다. 영화가 정해진 순서로 나타나지 않습니다. 예를 들어 우리는 영화를 연도별로 정렬하고 싶을 수 있습니다. 이를 위해 order 함수를 사용합니다. order 함수는 필드 목록과 정렬 방향을 지정하여 문서를 해당 방식으로 정렬합니다. releaseYear를 기준으로 영화를 정렬하고 싶다면 order(releaseYear)를 사용할 수 있습니다. 다음과 같습니다:

*[_type == 'movie' && releaseYear >= 1979] | order(releaseYear) {
  _id, title, releaseYear
}

(여기서 order() 함수 앞에 | 연산자가 필요합니다. 나중에 더 자세히 설명하겠습니다.)

GROQ 문을 데이터 흐름으로 생각합니다. 먼저 모든 것(*)이 [_type == 'movie' && ...] 필터를 통과한 다음, 해당 영화가 order() 함수를 통해 정렬되고, 그 결과로 projection {_id, title, ...}이 매핑되어 반환됩니다.

order 함수는 필드 목록을 받으며, 필요에 따라 각 필드에 대한 정렬 방향을 지정할 수 있습니다. 예를 들어 영화를 연도별로 정렬하고, 각 연도 내에서는 제목별로 알파벳순으로 정렬하려면 다음과 같은 정렬을 사용할 수 있습니다: order(releaseYear, title). 가장 최신 영화를 먼저 표시하려면 다음과 같이 정렬 방향을 반대로 지정할 수 있습니다: order(releaseYear desc, title).

팁: asc는 "오름차순", desc는 "내림차순"을 의미합니다. 정렬 방향을 지정하지 않으면 Sanity는 오름차순으로 정렬하는 것으로 간주합니다.

결과 집합 잘라내기

마지막으로 이 쿼리에 대한 마지막 문제가 있습니다. 세계에는 수많은 영화가 있습니다. 데이터셋에는 수만 개의 영화가 포함될 수 있습니다. 표시할 목록의 일부를 설명하는 방법이 필요합니다. 이는 선택자를 사용하여 수행됩니다. 첫 번째 영화만 원한다면 [0]을 추가할 수 있습니다. 이는 배열 접근자와 정확히 동일하게 작동하며 첫 번째 요소만 반환합니다. 범위 연산자를 사용하여 슬라이스를 가져올 수도 있습니다. 예를 들어 [0...100]은 0부터 99까지의 인덱스를 통해 첫 100개의 영화를 반환합니다. [1023...1048] 또는 다른 원하는 슬라이스를 요청할 수도 있습니다. 따라서 다음과 같이 설명할 수 있습니다. 쿼리는 다음과 같습니다:

*[_type == 'movie' && releaseYear >= 1979] | order(releaseYear) {
  _id, title, releaseYear
}[0...100]

참조와 조인

Sanity에서 참조(reference)는 한 문서에서 다른 문서로의 링크입니다. 표준 참조는 "강한"(hard) 참조로서, 문서가 다른 문서를 참조할 때 대상 문서가 존재해야 하며 참조가 제거될 때까지 실제로 삭제되지 않도록 방지됩니다. (참조된 문서를 삭제할 수 없습니다.) (참조 대상을 유지하지 않는 "약한 참조(weak reference)"도 있습니다. _weak 키를 참조 개체에 추가하여 만들 수 있습니다. 예를 들어 {_ref: "<문서 ID>", _weak: true}와 같이 작성하면 됩니다.)

간단하게 생각해서 "person" 타입의 문서가 다음과 같다고 가정해봅시다:

{
  _id: "ridley-scott",
  _type: "person",
  name: "Ridley Scott"
}

간단하게 유지하기 위해, 아래와 같이 각 영화에는 참조로서 "director"라는 필드가 있을 수 있습니다:

{
  _id: "alien",
  _type: "movie",
  title: "Alien",
  releaseYear: 1979,
  director: { _ref: "ridley-scott" }
}

Sanity 고유의 필드는 밑줄로 시작하며, 문서 내에서 _ref 키를 포함하는 객체는 강한 참조가 됩니다.

참조 확장

이제 이 참조를 사용하여 유용한 작업을 수행할 수 있습니다. 가장 기본적인 작업은 참조를 확장하는 것입니다. 이전에 살펴본 영화 쿼리를 다시 살펴보겠습니다.

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear
}

반환된 결과에 감독을 포함하려는 경우, 우리가 아는 것이 없다면 다음과 같이 시도할 수 있습니다:

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear,
  director
}

그러나 간단히 감독을 포함한다고하면, 실제로는 문서의 director 필드에 있는 내용이 반환되어 참조 설명의 문자 그대로가 됩니다:

[
  {
    _id: "alien",
    title: "Alien",
    releaseYear: "1979",
    director: {
      _ref: "ridley-scott"
    }
  },
   (다른 영화)
]

이는 우리가 원하는 것이 아니며, 해당 참조를 따라가고 싶습니다! 참조를 따라가도록 Sanity에 지시하기 위해 dereferencing 연산자 ->를 추가합니다:

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear,
  director->
}

이제 유용합니다. 다음과 같은 결과를 얻게됩니다:

[
  {
    _id: "alien",
    title: "Alien",
    releaseYear: "1979",
    director: {
      _id: "ridley-scott",
      _type: "person",
      name: "Ridley Scott"
    }
  },
   (다른 영화)
]

그런 다음 감독에 대한 메타데이터를 모두 제거하고 싶을 수도 있습니다. 감독에 대한 별도의 프로젝션을 추가할 수 있습니다:

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear,
  director->{name}
}

쿼리는 이제 우리가 원하는 대로 이름 속성만 포함된 감독을 반환합니다:

{
  _id: "alien",
  title: "Alien",
  releaseYear: "1979",
  director: {
    name: "Ridley Scott"
  }
}

하지만 더 나은 방법이 있습니다. 프로젝션에서 기존 문서의 기존 필드에 제한되지 않고, 실제로 새 필드를 선언할 수도 있습니다. 예를 들어 우리가 간결한 영화 목록을 작성하고 제목, 연도 및 감독 이름만 원한다고 가정해봅시다. 우리는 이름을 추출하고 새 필드에 넣어 다음과 같이 수행할 수 있습니다:

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear,
  "directorName": director->name
}

이제 쿼리는 우리가 원하는 대로 원하는 형식으로 반환됩니다:

{
  _id: "alien",
  title: "Alien",
  releaseYear: "1979",
  directorName: "Ridley Scott"
}

참조 배열 확장(Expanding references)

위의 예제는 참조를 확장하는 방법을 보여주지만, 때로는 참조 배열을 다룰 때도 있습니다. 위의 예제에서 우리는 프로듀서를 추가하고 싶다고 가정해봅시다. 스키마에서 이를 설정하는 방법에 대한 자세한 내용은 배열 문서에서 찾을 수 있지만, 데이터를 쿼리하는 방법에 대해 고려해보겠습니다.

이 수정된 예제에서 다음과 같은 쿼리를 살펴보겠습니다:

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear, director,
  producers[]
}

producers 뒤에 대괄호를 사용했는데, 이는 배열임을 나타냅니다. producers 뒤에 s를 사용한 것에 유의하세요. 스키마의 명명 규칙은 GROQ에 영향을 주지 않습니다(올바른 이름만 사용하면 됩니다). 배열에는 복수형 형태를 사용하는 것을 권장합니다.

이제 다음과 같은 결과를 얻을 수 있습니다:

[
  {
    _id: "alien",
    title: "Alien",
    releaseYear: "1979",
    director: {
      _ref: "ridley-scott"
    }
    producers: [
      {
        _key: "<uniqueKey1>",
        _type: "reference",
        _ref: "gordon-carroll"
      },
      {
        _key: "<uniqueKey2>",
        _type: "reference",
        _ref: "david-giler"
      },
      {
        _key: "<uniqueKey3>",
        _type: "reference",
        _ref: "walter-hill"
      },
    ]
  },
   (다른 영화)
]

이전과 마찬가지로 각 프로듀서에 대한 세부 정보가 반환되지 않습니다. 우리는 참조 확장을 위해 다시 한 번 참조 해체 연산자 (->)를 사용할 것입니다. 그러나 배열을 탐색하기 위해 대괄호는 필수입니다.

*[_type == 'movie' && releaseYear >= 1979]{
  _id, title, releaseYear, director,
  producers[]->
}

이제 참조 배열의 각 프로듀서에 대한 전체 세부 정보가 반환됩니다. 단일 참조와 마찬가지로 프로젝션 및 노출 프로젝션을 사용할 수 있습니다(프로젝션은 참조 연산자 뒤에 위치해야 함).

주의:
대괄호를 잊어버려 참조 배열을 확장하는 것을 잊을 수 있습니다(즉, producers-> 대신 producers[]->를 쿼리하는 경우 전체 값이 null인 단일 값이 반환됩니다). GROQ 탐색의 특성상 이것은 어려울 수 있습니다.

참조로 필터링하기

참조를 다룰 때 references()라는 유용한 함수가 있습니다. 이 함수를 사용하여 특정 다른 문서를 참조하는 문서만 선택하는 필터로 사용할 수 있습니다. 예를 들어 Ridley Scott가 참여한 모든 영화를 나열하려면 다음과 같습니다:

*[_type == 'movie' && references('ridley-scott')]

첫 번째 조인

첫 번째 실제 조인을 작성해 보겠습니다: 사람들의 목록을 작성하고 그들이 참여한 모든 영화를 포함하고 싶다고 가정해봅시다. "person" 타입의 문서를 쿼리하지만 각 사람의 프로젝션에서는 그들이 참여한 영화를 요청합니다. 이를 위해 부모 연산자 ^를 간단히 소개하겠습니다. 먼저 쿼리를 살펴보겠습니다:

*[_type == "person"]{
  _id, name,
  "movies": *[_type == "movie" && references(^._id)].title
}

조인에서 부모 연산자는 "부모" 문서를 참조하는 방법입니다. 이 예에서 "person" 타입 문서에 대한 외부 쿼리는 일련의 사람들을 가져오고 각 사람에 대해 _idname을 반환합니다. 그런 다음 해당 사람을 참조하는 영화를 가져오고자합니다.

이제 새로운 "movies" 필드를 선언하여 "movie" 타입 문서에 대한 새 쿼리를 시작합니다. 그러나 각 사람마다 영화 쿼리를 해당 사람을 참조하는 영화로 제한하려고 합니다. 이를 위해 사람의 _id가 필요하지만 영화 쿼리에서 _id를 작성하면 영화의 _id를 참조합니다.

사람 레코드의 필드로 이동하기 위해 부모 레벨을 "위로" 이동하는 부모 연산자 ^를 사용합니다. 따라서 ^는 영화 쿼리에 대해 특정 "person" 문서를 참조하며, ^._id는 해당 사람의 _id이며, ^.name은 해당 사람의 이름입니다. 따라서 위의 쿼리에서 references(^._id)라고 말할 때, 현재 사람을 참조하는 영화로 영화를 제한합니다.

노출 프로젝션 (Naked Projections)

이 쿼리에서 아직 이야기하지 않은 새로운 것이 하나 더 있습니다. 영화 하위 쿼리를 다음과 같이 작성할 수도 있습니다:

*[_type == "movie" && references(^._id)]{title}

영화 목록은 다음과 같을 것입니다:

"movies": [{title: "Alien"}, {title: "Blade Runner"},]

제목만 원하기 때문에 "노출 프로젝션(naked projection)"을 사용할 수 있습니다. 원하는 필드를 이름으로 지정하면 다음과 같이 값의 간단한 배열을 얻을 수 있습니다:

"movies": [“Alien”, “Blade Runner”,]

따라서 완전성을 위해 위의 전체 사람 w/movies 쿼리의 결과는 다음과 같을 수 있습니다:

[
  {
    _id: "river-phoenix",
    name: "River Phoenix",
    movies: ["My Own Private Idaho", "Stand By Me",]
  },
  {
    _id: "ridley-scott",
    name: "Ridley Scott",
    movies: ["Alien", "Blade Runner",]
  },]

추가 필터링 방법

Sanity는 문서를 필터링하기 위해 점점 더 많은 방법을 지원합니다. 우리는 _type == 'movie'releaseYear >= 1979와 같은 간단한 속성 비교를 보여주었습니다. references() 함수를 사용하여 참조에 의한 필터링을 보여주었습니다. 추가로 다음과 같은 기능을 지원합니다:

  • match 연산자를 사용한 텍스트 검색, 예: *[title match "Alien*"]
  • 필드의 존재에 따른 필터링, 예: *[defined(status)], status 속성이 설정된 문서에만 일치하는 문서를 선택합니다.
  • 배열에서 값이 일치하는 in 연산자, 예: *["sci-fi" in genres], genres가 배열이고 해당 배열이 "sci-fi" 값을 포함하는 모든 문서와 일치합니다.
  • 물론 이러한 필터를 &&(그리고), ||(또는), !(부정)과 결합할 수 있습니다. 예를 들어 *[_type == "movie" && (!("sci-fi" in genres) || releaseYear >= 1979)]와 같이 사용할 수 있습니다.
    GROQ 기능 집합에 대한 전체 참조를 준비 중입니다. 그 동안에는 치트 시트에 포함된 포괄적인 예제를 참조하실 수 있습니다.

프로젝션 내에서의 쿼리

GROQ에서 유용한 점은 필터링과 프로젝션을 프로젝션 내부에서도 사용할 수 있다는 것입니다. 예를 들어, 건축가를 위한 작업을하는 경우 각 프로젝트에는 여러 개의 이정표가 있습니다. 문서는 다음과 같을 수 있습니다:

{
  _id: "timmerhuis"
  _type: "project",
  title: "Timmerhuis",
  milestones: [
    {status: "competition", year: 2009},
    {status: "design-development", year: 2011},
    {status: "breaking-ground", year: 2013},
    {status: "completed", year: 2015}
  ]
}

그리고 우리가 생성하려는 보기는 프로젝트의 현재 상태를 보여주는 것입니다. 이를 위해 가장 최신 이정표를 찾고 해당 상태 태그를 추출할 수 있습니다. 이를 GROQ로 다음과 같이 수행할 수 있습니다:

*[_type == "project"]{
  _id, title,
  "status": milestones|order(year desc)[0].status
}

status 쿼리인 milestones|order(year desc)[0].status를 자세히 살펴보겠습니다:

먼저, 우리는 프로젝트에 포함된 (순서가 지정되지 않은 경우도 있음) 이정표 목록을 가져오기 위해 milestones 필드를 사용합니다. | 파이프 연산자를 사용하여이 배열의 내용을 year를 기준으로 내림차순으로 정렬하는 order 함수에 보냅니다. 그런 다음 첫 번째 요소 [0] (가장 최신 이정표) 만 선택하고 해당 상태 필드의 값을 반환합니다. 따라서 이제 우리의 프로젝트 목록은 다음과 같이 될 것입니다:

[
  {
    _id: "timmerhuis",
    title: "Timmerhuis",
    status: "completed"
  },]

또 다른 멋진 기능을 시도해보겠습니다. 이 객체의 내용을 쿼리하는 것입니다. 상태 필드가 아니라 프로젝트가 완료되었는지 여부를 나타내는 부울 플래그만 원한다고 가정해봅시다. 이를 다음과 같이 수행할 수 있습니다:

*[_type == "project"]{
  _id, title,
  "completed": count(milestones[status == 'completed']) > 0
}

여기서 우리는 milestones를 가져오지만 상태가 "completed"인 것만 선택합니다. 그런 다음 이 필터와 일치하는 마일스톤 수를 count()합니다. 그 수가 0보다 크면 결과는 true입니다. 따라서 이제 결과는 다음과 같을 수 있습니다:

[
  {
    _id: "timmerhuis",
    title: "Timmerhuis",
    completed: true
  },]

파이프 연산자에 대한 몇 가지 코멘트

위의 프로젝트 상태 예제에서 우리는 두 번째로 파이프 연산자 |를 사용했습니다. 이를 좀 더 자세히 살펴보겠습니다:

*[_type == "project"]{
  _id, title,
  "status": milestones | order(year desc)[0].status
}

파이프 연산자는 왼쪽 피연산자에서 나온 결과를 오른쪽에 있는 연산에 전달합니다. "그런데 모든 GROQ 문이 그렇지 않은가요?"라고 묻는 소리가 들립니다. 맞습니다.

파이프 함수 (예 : 프로젝트 상태 예제에서의 order())를 사용하는 경우와 같이 일부 상황에서는 명시적인 파이프 연산자가 필요합니다. milestones order(year desc)는 구문 오류가 될 것이므로 파이프 함수는 파이프 연산자로 시작되어야 합니다. 이렇게 사용합니다: milestones | order(year desc). score()는 파이프 함수의 또 다른 예입니다. 따라서 파이프 연산자 앞에 나와야 합니다.

프로젝션에는 파이프 연산자를 붙일 수 있지만 선택 사항입니다. Expression { Projection }Expression | { Projection }은 모두 유효합니다.

파이프 연산자는 다른 문맥에서 유효하지 않으며 오류가 발생합니다.

배열과 프로젝션에 대한 세부 사항

다음과 같이 깊은 구조를 가진 문서를 고려해 봅시다:

{
  _id: "alien",
  _type: "movie",
  title: "Alien",
  poster: {
    asset: {_ref: "image-1234"}
  },
  images: [
    {
      caption: "Sigourney Weaver and the cat Jones on set",
      asset: {_ref: "image-1235"}
    },
    {
      caption: "Bolaji Badejo suiting up for the role of the Alien",
      asset: {_ref: "image-1236"}
    },
  ]
}

따라서 우리에게는 포스터 이미지와 다른 이미지의 배열이 있는 영화가 있습니다. 각 이미지에는 캡션, 그리고 URL을 포함한 특정 이미지에 대한 모든 메타데이터를 나타내기 위해 자산 레코드에 대한 참조가 있습니다. 간소화된 자산 레코드는 다음과 같을 수 있습니다:

{
  _id: "image-1234",
  _type: "sanity.imageAsset",
  url: "http:///cdn.sanity.io/images/…"
}

이제 우리는 포스터 이미지 URL을 검색하고 각 영화에 연결할 수 있습니다:

*[_type == "movie"]{
  title,
  "posterImage": poster.asset->url
}

그러나 다른 이미지에 대해서도 동일한 작업을 하고 싶다면 어떻게 해야 할까요? images 필드는 배열이므로 images.asset->url과 같이 그대로 사용할 수 없습니다. 어떻게든 배열의 각 멤버에 asset->url 부분을 적용해야 합니다. 이를 위해 빈 필터를 추가해야 합니다. 이렇게 하면 images[].asset->url을 사용하여 이미지 URL을 간단한 배열로 반환할 수 있습니다. 따라서 전체 쿼리는 다음과 같을 것입니다:

*[_type == "movie"]{
  title,
  "imageUrls": images[].asset->url
}

이렇게하면 다음과 같은 결과가 생성됩니다:

[
  {
    title: "Alien",
    imageUrls: ["http://cdn.sanity.io/…", "http://cdn.sanity.io/…"]
  },]

이미지와 관련된 더 풍부한 데이터 세트를 원한다면 다음과 같이 일반적인 프로젝션을 사용할 수 있습니다 (프로젝션을 각 배열 멤버에 적용하려면 빈 필터를 추가하는 것에 주의해야 함):

*[_type == "movie"]{
  title,
  "images": images[]{
    caption,
    "url": asset->url,
  }
}

이제 결과는 다음과 같이 될 것입니다:

[
  {
    title: "Alien",
    images: [
      {
        caption: "Sigourney Weaver and the cat Jones on set",
        url: "http://cdn.sanity.io/…"
      },
      {
        caption: "Bolaji Badejo suiting up for the role of the Alien",
        url: "http://cdn.sanity.io/…"
      }
    ]
  },]

생략 연산자

때로는 문서의 일부 속성을 계산하고 싶지만, 여전히 모든 속성 집합을 반환하고 싶을 수 있습니다. 이는 사용자 정의 필드를 추가하기 위해 프로젝션이 필요하지만, 프로젝션을 지정하면 포함하려는 모든 필드를 명시적으로 나열해야 한다는 문제가 있습니다. 영화에서 배우의 수를 세고자 다음과 같이 작업하려고 할 때 문제가 발생합니다:

*[_type == "movie"]{
  "actorCount": count(actors)
}

이에는 문제가 있습니다. 사용자 정의 필드를 추가하려고 했지만, 프로젝션이 필요했기 때문에 이제 얻게 된 것은 다음과 같습니다:

[
  {actorCount: 3},
  {actorCount: 27},
  {actorCount: 15}
]

우리가 원한 것은 사용자 정의 필드와 일반 필드를 함께 얻는 것입니다. 이는 생략 연산자를 사용하여 달성할 수 있습니다. 다음과 같이 생략 연산자를 추가하여 명시적으로 지정한 필드뿐만 아니라 모든 것을 가져오도록 지정합니다:

*[_type == "movie"]{
  "actorCount": count(actors),
  ...
}

이렇게 하면 다음과 같은 결과가 나타납니다:

{
  {
    title: "Alien",
    releaseYear: 1979,
    actorCount: 23,
    // 그리고 많은 다른 필드, 아마도
  },
  // 그리고 많은 영화
}

생략 연산자의 위치

GROQ API v1에서는 생략 연산자의 위치가 중요하지 않았습니다. 명시적인 속성이 생략 연산자 다음에 오더라도 생략 연산자로 반환된 속성을 덮어씌웠습니다.

age23인 경우, 어떤 속성이 나이와 같다고 가정해 봅시다.

// GROQ API v1
*[]{
  ...,
  'age': 45 // 이는 생략에서 반환된 나이 속성을 덮어씌웁니다. 따라서 age는 45입니다.
}

*[]{
  'age': 45,
  ... // 생략에서 반환된 나이 값은 명시적으로 설정된 값보다 우선순위가 낮으므로 age는 45입니다.
}

GROQ API v2021-03-25부터는 생략 연산자의 위치가 중요해졌습니다. 생략에서 반환된 속성을 오버라이드하려면 명시적으로 설정된 속성이 생략 연산자 뒤에 오면 됩니다. 즉, GROQ API v2021-03-25부터는 프로젝션에서 가장 마지막에 있는 속성이 이기게 됩니다. 실제로 그 속성이 생략에서 반환된 것이더라도 그렇습니다.

// GROQ API v2021-03-25 이후

*[]{
  ...,
  'age': 45 // 이는 생략에서 반환된 나이 속성을 덮어씌웁니다. 따라서 age는 45입니다.
}

*[]{
  'age': 45,
  ... // 생략에서 반환된 나이 값은 명시적으로 설정된 값보다 우선순위가 낮으므로 age는 23입니다.
}

이러한 차이점은 역참조할 때 관찰될 수 있습니다. v1에서는 명시적인 역참조 연산자를 생략 연산자 앞이나 뒤에 놓을 수 있었으며, 두 경우 모두 해당 문서를 따르게 되었습니다. 그러나 v2021-03-25부터는 생략 연산자 뒤에 명시적인 역참조를 배치하면 예상한 동작을 수행하며, 생략 연산자를 마지막에 배치하면 원래의 (역참조되지 않은) 속성이 이기게 되어 _ref_type만 반환하게 됩니다.

팁: 생략 연산자를 사용할 때는 프로젝션에서 가장 먼저 나열해야 합니다. 뒤에 명시적으로 나열된 속성은 생략에서 반환된 동일한 속성을 덮어씁니다. 이는 일반적으로 원하는 동작입니다.

* 로 시작하지 않는 쿼리

처음에 대부분의 GROQ 쿼리가 *로 시작한다고 말했지만, 그럴 필요는 없습니다. 유효한 GROQ 식은 모든 쿼리의 전체일 수 있습니다. 다음은 유효한 쿼리입니다:

count(*)

이는 데이터 세트에 있는 문서의 수를 반환합니다. 다음도 유효합니다:

count(*[name match "sigourney"]) > 0

이는 데이터 세트의 모든 문서 중 "sigourney"라는 단어가 포함된 이름 필드가 있는지 여부를 반환합니다.

더 유용하게도 프로젝션이 외부 문장이 될 수도 있습니다. 다음과 같이 세 개의 완전히 별개의 쿼리를 하나의 쿼리로 결합하고 그 결과를 포함하는 개체를 반환합니다. 이는 페이지 로드 속도를 높이는 유용한 방법입니다. 이러한 방식으로 쿼리를 결합함으로써 캐시 가능한 단일 쿼리에서 웹 페이지의 모든 핵심 콘텐츠를로드할 수 있습니다.

{
  "mainStory": *[_id == "story-1234"],
  "campaign": *[_id == "campaign-1234"],
  "topStories": *[_type == "story"] | order(publishAt desc) [0..10]
}

쿼리 최적화

다른 쿼리 언어와 마찬가지로 GROQ 쿼리를 개발하고 반복할 때 성능에 대해 인식하는 것이 중요합니다.

마지막으로

그러면 이로써 GROQ의 일상적인 사용에 필요한 대부분을 이해하는 데 필요한 내용을 다루었습니다. Query Cheat Sheet, GROQ Arcade 및 현재 지원되는 모든 연산자 및 함수에 대한 예제가 포함된 참조 문서를 확인해야 합니다.

0개의 댓글