Data Connect şemaları, sorguları ve mutasyonları

Firebase Data Connect, Google Cloud SQL ile yönetilen PostgreSQL örnekleriniz için bağlayıcılar oluşturmanıza olanak tanır. Bu bağlayıcılar, verilerinizi kullanmak için bir şemanın, sorguların ve mutasyonların bir kombinasyonudur.

Başlangıç kılavuzunda, PostgreSQL için bir film yorumu uygulaması şeması tanıtıldı. Bu kılavuzda, PostgreSQL için Data Connect şemalarının nasıl tasarlanacağına daha ayrıntılı bir şekilde değinilmektedir.

Bu kılavuzda, Data Connect sorguları ve mutasyonları şema örnekleriyle eşleştirilir. Data Connect şemaları hakkındaki bir kılavuzda neden sorgular (ve mutasyonlar) ele alınıyor? Diğer GraphQL tabanlı platformlar gibi Firebase Data Connect de sorgu öncelikli bir geliştirme platformudur. Bu nedenle, geliştirici olarak veri modellemenizde müşterilerinizin ihtiyaç duyduğu verileri düşünürsünüz. Bu veriler, projeniz için geliştirdiğiniz veri şemasını büyük ölçüde etkiler.

Bu kılavuzda, yeni bir film yorumları şemasıyla başlanır, ardından bu şemadan türetilen sorgular ve mutasyonlar ele alınır ve son olarak temel Data Connect şemasına eşdeğer bir SQL listesi sağlanır.

Film yorumu uygulamasının şeması

Kullanıcıların film yorumları gönderip görüntülemesine olanak tanıyan bir hizmet oluşturmak istediğinizi varsayalım.

Bu tür bir uygulama için ilk bir şemaya ihtiyacınız vardır. Daha sonra karmaşık ilişkisel sorgular oluşturmak için bu şemayı genişleteceksiniz.

Film tablosu

Filmler şemasında aşağıdaki gibi temel yönergeler bulunur:

  • @table(name) ve @col(name) kullanarak SQL tablo ve sütun adlarını özelleştirebilirsiniz. Belirtilmemişse Data Connect, snake_case adları oluşturur.
  • @col(dataType) tuşlarına basarak SQL sütun türlerini özelleştirebilirsiniz.
  • @default, ekleme sırasında SQL sütunu varsayılan değerlerini yapılandırmak için kullanılır.

Daha fazla bilgi için @table, @col ve @default ile ilgili referans dokümanlarına göz atın.

# Movies
type Movie @table(name: "movie", key: "id") {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int
  genre: String @col(dataType: "varchar(20)")
  rating: Int
  description: String
}

Anahtar skalerler ve sunucu değerleri

Film yorumu uygulamasına daha ayrıntılı bakmadan önce Data Connect anahtar skalerlerini ve sunucu değerlerini tanıtalım.

Anahtar skalerler, Data Connect'in şemalarınızdaki anahtar alanlardan otomatik olarak derlediği kısa nesne tanımlayıcılardır. Anahtar skalerler verimlilikle ilgilidir ve verilerinizin kimliği ve yapısı hakkındaki bilgileri tek bir çağrıda bulmanızı sağlar. Özellikle yeni kayıtlarda sıralı işlemler yapmak istediğinizde ve yaklaşan işlemlere iletilecek benzersiz bir tanımlayıcıya ihtiyaç duyduğunuzda ve ayrıca daha karmaşık işlemler yapmak için ilişkisel anahtarlara erişmek istediğinizde kullanışlıdır.

Sunucu değerlerini kullanarak, expr bağımsız değişkenindeki belirli sunucu tarafı CEL ifadelerine göre depolanan veya kolayca hesaplanabilen değerleri kullanarak sunucunun tablolarınızdaki alanları dinamik olarak doldurmasına izin verebilirsiniz. Örneğin, bir işlem isteğinde (updatedAt: Timestamp! @default(expr: "request.time")) depolanan saat kullanılarak alana erişildiğinde zaman damgası uygulanmış bir alan tanımlayabilirsiniz.

Film meta verileri tablosu

Şimdi film yönetmenlerini takip edip Movie ile bire bir ilişki oluşturalım.

İlişki tanımlamak için referans alanını ekleyin.

Yabancı anahtar kısıtlamasını özelleştirmek için @ref yönergesini kullanabilirsiniz.

  • @ref(fields) kullanarak yabancı anahtar alanlarını belirtin.
  • @ref(references) kullanarak hedef tabloda referans verilen alanları belirtin. Bu referans varsayılan olarak birincil anahtarı kullanır ancak @unique içeren alanlar da desteklenir.

Daha fazla bilgi için @ref ile ilgili referans dokümanlarına göz atın.

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata @table {
  # @unique ensures that each Movie only has one MovieMetadata.
  movie: Movie! @unique
  # Since it references to another table type, it adds a foreign key constraint.
  #  movie: Movie! @unique @ref(fields: "movieId", references: "id")
  #  movieId: UUID! <- implicitly added foreign key field
  director: String
}

Actor ve MovieActor

Ardından, filmlerinizde rol alacak aktörler istiyorsunuz. Filmler ile aktörler arasında çoklu ilişki olduğundan bir birleştirme tablosu oluşturun.

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID! @default(expr: "uuidV4()")
  name: String! @col(dataType: "varchar(30)")
}
# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary keys of this table
# In this case, the keys are [movieId, actorId], the foreign key fields of the reference fields [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  movie: Movie!
  # movieId: UUID! <- implicitly added foreign key field
  actor: Actor!
  # actorId: UUID! <- implicitly added foreign key field
  role: String! # "main" or "supporting"
  # optional other fields
}

Kullanıcı

Son olarak, uygulamanızın kullanıcıları.

# Users
# Suppose a user can leave reviews for movies
type User @table {
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
}

Desteklenen veri türleri

Data Connect, @col(dataType:) kullanılarak PostgreSQL türlerine atamalarla aşağıdaki skaler veri türlerini destekler.

Data Connect türü GraphQL yerleşik türü veya
Data Connect özel türü
Varsayılan PostgreSQL türü Desteklenen PostgreSQL türleri
(parantez içinde takma ad)
Dize GraphQL metin text
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Kayan GraphQL float8 float4 (reel)
float8 (çift hassasiyet)
numeric (ondalık)
Boole GraphQL boolean boolean
UUID Özel uuid uuid
Int64 Özel bigint int8 (bigint, bigserial)
numeric (ondalık)
Tarih Özel tarih tarih
Zaman damgası Özel timestamptz

timestamptz

Not: Yerel saat dilimi bilgileri depolanmaz.
PostgreSQL bu tür zaman damgalarını UTC olarak dönüştürüp depolar.

Vector Özel vector

vektör

Vertex AI ile vektör benzerliği araması yapma başlıklı makaleyi inceleyin.

  • GraphQL List, tek boyutlu bir diziyle eşlenir.
    • Örneğin, [Int] int5[] ile, [Any] ise jsonb[] ile eşlenir.
    • Data Connect iç içe dizileri desteklemez.

Sorgu ve mutasyon oluşturmak için oluşturulan alanları kullanma

Data Connect sorgularınız ve mutasyonlarınız, şemanızdaki türlere ve tür ilişkilerine göre otomatik olarak oluşturulan bir Data Connect alan grubunu genişletir. Bu alanlar, şemanızı her düzenlediğinizde yerel araçlar tarafından oluşturulur.

  • Başlangıç kılavuzunda da belirtildiği gibi, Firebase konsolu ve yerel geliştirme araçlarımız, bu otomatik olarak oluşturulan alanları kullanarak size veri eklemek ve tablolarınızın içeriğini doğrulamak için kullanabileceğiniz ad hoc yönetimsel sorgular ve mutasyonlar sağlar.

  • Geliştirme sürecinizde, bu otomatik olarak oluşturulan alanlara göre bağlayıcılarınızda gruplandırılmış dağıtılabilir sorgular ve dağıtılabilir mutasyonlar uygularsınız.

Otomatik olarak oluşturulan alan adlandırma

Data Connect, şema türü beyanlarınıza göre otomatik olarak oluşturulan alanlar için uygun adları çıkarır. Örneğin, PostgreSQL kaynağıyla çalışırken Movie adlı bir tablo tanımlarsanız sunucu şunları oluşturur:

  • Tek tablolu kullanım alanlarında verileri okumak için movie (eq gibi bağımsız değişkenler göndererek tek tek sonuçları almak için tekil) ve movies (gt gibi bağımsız değişkenler ve orderby gibi işlemler göndererek sonuç listelerini almak için çoğul) gibi kullanıcı dostu adlara sahip alanlar. Data Connect, actors_on_movies veya actors_via_actormovie gibi açık adlara sahip çok tablolu, ilişkisel işlemler için de alanlar oluşturur.
  • movie_insert, movie_upsert gibi bilinen bir ada sahip verileri yazmak için alanlar

Şema tanımı dili, singular ve plural yönerge bağımsız değişkenlerini kullanarak alanlar için adların nasıl oluşturulacağını açıkça kontrol etmenize de olanak tanır.

Sorgular ve mutasyonlar için talimatlar

Data Connect, türleri ve tabloları tanımlarken kullandığınız yönergelere ek olarak sorguların ve mutasyonların davranışını geliştirmek için @auth, @check, @redact ve @transaction yönergelerini sağlar.

Direktif Geçerlilik kapsamı Açıklama
@auth Sorgular ve mutasyonlar Sorgu veya mutasyon için kimlik doğrulama politikasını tanımlar. Yetkilendirme ve doğrulama kılavuzuna bakın.
@check Yetkilendirme verisi arama sorguları Belirtilen alanların sorgu sonuçlarında bulunduğunu doğrular. Alan değerlerini test etmek için Common Expression Language (CEL) ifadesi kullanılır. Yetkilendirme ve doğrulama kılavuzuna bakın.
@redact Sorgular İstemciden gelen yanıtın bir bölümünü çıkartır. Yetkilendirme ve doğrulama kılavuzuna bakın.
@transaction Değişiklikler Bir mutasyonun her zaman bir veritabanı işleminde çalıştırılmasını zorunlu kılar. Film uygulaması mutasyon örneklerine bakın.

Film yorumu veritabanı için sorgular

Sorgu işlemi türü beyanı, işlem adı, sıfır veya daha fazla işlem bağımsız değişkeni ve bağımsız değişken içeren sıfır veya daha fazla yönergeyle bir Data Connect sorgusu tanımlarsınız.

Hızlı başlangıç kılavuzundaki örnek listEmails sorgusunda parametre yoktu. Elbette, sorgu alanlarına iletilen veriler çoğu durumda dinamik olacaktır. Sorgu tanımının bileşenlerinden biri olarak değişkenlerle çalışmak için $variableName söz dizimini kullanabilirsiniz.

Dolayısıyla aşağıdaki sorguda:

  • query türü tanımı
  • ListMoviesByGenre işlemi (sorgu) adı
  • Tek değişkenli $genre işlem bağımsız değişkeni
  • Tek bir yönerge (@auth).
query ListMoviesByGenre($genre: String!) @auth(level: USER)

Her sorgu bağımsız değişkeni için bir tür beyanı, String gibi yerleşik bir tür veya Movie gibi şemada tanımlanmış özel bir tür gerekir.

Giderek daha karmaşık hale gelen sorguların imzasını inceleyelim. Dersi, dağıtılabilir sorgularınızı oluşturmak için kullanabileceğiniz güçlü ve kısa ilişki ifadelerini tanıtarak sonlandıracaksınız.

Sorgulardaki temel skalerler

Ancak öncelikle, temel skalerlerle ilgili bir not.

Data Connect, _Key ile tanımlanan anahtar skalerler için özel bir tür tanımlar. Örneğin, Movie tablomuzdaki bir anahtar skalerinin türü Movie_Key'dur.

Anahtar skalerleri, otomatik olarak oluşturulan çoğu okuma alanı tarafından döndürülen bir yanıt olarak veya elbette skaler anahtarı oluşturmak için gereken tüm alanları aldığınız sorgulardan alırsınız.

Çalışan örneğimizdeki movie gibi tekil otomatik sorgular, bir anahtar skaler kabul eden bir anahtar bağımsız değişkenini destekler.

Bir anahtar skalerini değişmez değer olarak iletebilirsiniz. Ancak, giriş olarak temel skaler göndermek için değişkenler tanımlayabilirsiniz.

query GetMovie($myKey: Movie_Key!) {
  movie(key: $myKey) { title }
}

Bunlar, istek JSON'unda aşağıdaki gibi (veya diğer serileştirme biçimlerinde) sağlanabilir:

{
  # 
  "variables": {
    "myKey": {"foo": "some-string-value", "bar": 42}
  }
}

Özel skaler ayrıştırma sayesinde, Movie_Key değişken içerebilen nesne söz dizimi kullanılarak da oluşturulabilir. Bu yöntem, genellikle bir nedenle tek tek bileşenleri farklı değişkenlere bölmek istediğinizde yararlıdır.

Sorgularda takma ad kullanma

Data Connect, sorgularda GraphQL takma adlandırmasını destekler. Takma adlar sayesinde, bir sorgunun sonuçlarında döndürülen verileri yeniden adlandırabilirsiniz. Tek bir Data Connect sorgusu, sunucuya tek bir verimli istek göndererek birden fazla filtre veya başka sorgu işlemleri uygulayabilir ve aynı anda birkaç "alt sorgu" yayınlayabilir. Döndürülen veri kümesinde ad çakışmalarını önlemek için alt sorguları ayırt etmek üzere takma adlar kullanırsınız.

Aşağıda, bir ifadenin mostPopular takma adını kullandığı bir sorgu verilmiştir.

query ReviewTopPopularity($genre: String) {
  mostPopular: review(first: {
    where: {genre: {eq: $genre}},
    orderBy: {popularity: DESC}
  }) {  }
}

Filtre içeren basit sorgular

Data Connect sorguları, tüm yaygın SQL filtreleriyle ve sıralama işlemleriyle eşlenir.

where ve orderBy operatörleri (tekil, çoğul sorgular)

Tablodaki eşleşen tüm satırları (ve iç içe geçmiş ilişkilendirmeleri) döndürür. Filtreyle eşleşen bir kayıt yoksa boş bir dizi döndürür.

query MovieByTopRating($genre: String) {
  mostPopular: movies(
     where: { genre: { eq: $genre } }, orderBy: { rating: DESC }
  ) {
    # graphql: list the fields from the results to return
    id
    title
    genre
    description
  }
}

query MoviesByReleaseYear($min: Int, $max: Int) {
  movies(where: {releaseYear: {le: $max, ge: $min}}, orderBy: [{releaseYear: ASC}]) {  }
}

limit ve offset operatörleri (tekil, çoğul sorgular)

Sonuçlarda sayfalandırma yapabilirsiniz. Bu bağımsız değişkenler kabul edilir ancak sonuçlarda döndürülmez.

query MoviesTop10 {
  movies(orderBy: [{ rating: DESC }], limit: 10) {
    # graphql: list the fields from the results to return
    title
  }
}

Dizi alanları için içerir

Bir dizi alanının belirtilen bir öğeyi içerip içermediğini test edebilirsiniz.

# Filter using arrays and embedded fields.
query ListMoviesByTag($tag: String!) {
  movies(where: { tags: { includes: $tag }}) {
    # graphql: list the fields from the results to return
    id
    title
  }
}

Dize işlemleri ve normal ifadeler

Sorgularınızda normal ifadeler de dahil olmak üzere normal dize arama ve karşılaştırma işlemleri kullanılabilir. Verimliliği artırmak için burada birkaç işlemi bir araya getirdiğinizi ve bunları takma adlarla açıklığa kavuşturduğunuzu unutmayın.

query MoviesTitleSearch($prefix: String, $suffix: String, $contained: String, $regex: String) {
  prefixed: movies(where: {title: {startsWith: $prefix}}) {...}
  suffixed: movies(where: {title: {endsWith: $suffix}}) {...}
  contained: movies(where: {title: {contains: $contained}}) {...}
  matchRegex: movies(where: {title: {pattern: {regex: $regex}}}) {...}
}

Birleştirilmiş filtreler için or ve and

Daha karmaşık mantık için or ve and kullanın.

query ListMoviesByGenreAndGenre($minRating: Int!, $genre: String) {
  movies(
    where: { _or: [{ rating: { ge: $minRating } }, { genre: { eq: $genre } }] }
  ) {
    # graphql: list the fields from the results to return
    title
  }
}

Karmaşık sorgular

Data Connect sorguları, tablolar arasındaki ilişkilere göre verilere erişebilir. İç içe yerleştirilmiş sorgular oluşturmak (ör. iç içe yerleştirilmiş veya ilgili bir türden veri ile birlikte bir tür için veri almak) amacıyla şemanızda tanımlanan nesne (bire bir) veya dizi (bir çok) ilişkilerini kullanabilirsiniz.

Bu tür sorgular, oluşturulan okuma alanlarında sihirli Data Connect _on_ ve _via söz dizimini kullanır.

İlk sürümümüzdeki şemada değişiklikler yapacaksınız.

Çoka-tek

Uygulamamıza yorumlar ekleyelim. Bunun için Review tablosu ve User'da değişiklikler yapalım.

# User table is keyed by Firebase Auth UID.
type User @table {
  # `@default(expr: "auth.uid")` sets it to Firebase Auth UID during insert and upsert.
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
  # The `user: User!` field in the Review table generates the following one-to-many query field.
  #  reviews_on_user: [Review!]!
  # The `Review` join table the following many-to-many query field.
  #  movies_via_Review: [Movie!]!
}

# Reviews is a join table tween User and Movie.
# It has a composite primary keys `userUid` and `movieId`.
# A user can leave reviews for many movies. A movie can have reviews from many users.
# User  <-> Review is a one-to-many relationship
# Movie <-> Review is a one-to-many relationship
# Movie <-> User is a many-to-many relationship
type Review @table(name: "Reviews", key: ["movie", "user"]) {
  user: User!
  # The user field adds the following foreign key field. Feel free to uncomment and customize it.
  #  userUid: String!
  movie: Movie!
  # The movie field adds the following foreign key field. Feel free to uncomment and customize it.
  #  movieId: UUID!
  rating: Int
  reviewText: String
  reviewDate: Date! @default(expr: "request.time")
}

Bire çok sorgu

Şimdi _via_ söz dizimini açıklamak için takma ad içeren bir sorguya bakalım.

query UserMoviePreferences($username: String!) @auth(level: USER) {
  users(where: { username: { eq: $username } }) {
    likedMovies: movies_via_Review(where: { rating: { ge: 4 } }) {
      title
      genre
    }
    dislikedMovies: movies_via_Review(where: { rating: { le: 2 } }) {
      title
      genre
    }
  }
}

Bire bir

Bu durumu görebilirsiniz. Aşağıda, şemada açıklama amaçlı değişiklikler yapılmıştır.

# Movies
type Movie
  @table(name: "Movies", singular: "movie", plural: "movies", key: ["id"]) {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int @col(name: "release_year")
  genre: String
  rating: Int @col(name: "rating")
  description: String @col(name: "description")
  tags: [String] @col(name: "tags")
}
# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata
  @table(
    name: "MovieMetadata"
  ) {
  # @ref creates a field in the current table (MovieMetadata) that holds the primary key of the referenced type
  # In this case, @ref(fields: "id") is implied
  movie: Movie! @ref
  # movieId: UUID <- this is created by the above @ref
  director: String @col(name: "director")
}


extend type MovieMetadata {
  movieId: UUID! # matches primary key of referenced type
...
}

extend type Movie {
  movieMetadata: MovieMetadata # can only be non-nullable on ref side
  # conflict-free name, always generated
  movieMetadatas_on_movie: MovieMetadata
}

Bire bir sorgu

_on_ söz dizimini kullanarak sorgu oluşturabilirsiniz.

# One to one
query GetMovieMetadata($id: UUID!) @auth(level: PUBLIC) {
  movie(id: $id) {
    movieMetadatas_on_movie {
      director
    }
  }
}

Çoka çok

Filmler oyunculara, oyuncular da filmlere ihtiyaç duyar. Bu iki tablo arasında MovieActors birleştirme tablosuyla modelleyebileceğiniz çoklu-çoklu bir ilişki vardır.

# MovieActors Join Table Definition
type MovieActors @table(
  key: ["movie", "actor"] # join key triggers many-to-many generation
) {
  movie: Movie!
  actor: Actor!
}

# generated extensions for the MovieActors join table
extend type MovieActors {
  movieId: UUID!
  actorId: UUID!
}

# Extensions for Actor and Movie to handle many-to-many relationships
extend type Movie {
  movieActors: [MovieActors!]! # standard many-to-one relation to join table
  actors: [Actor!]! # many-to-many via join table

  movieActors_on_actor: [MovieActors!]!
  # since MovieActors joins distinct types, type name alone is sufficiently precise
  actors_via_MovieActors: [Actor!]!
}

extend type Actor {
  movieActors: [MovieActors!]! # standard many-to-one relation to join table
  movies: [Movie!]! # many-to-many via join table

  movieActors_on_movie: [MovieActors!]!
  movies_via_MovieActors: [Movie!]!
}

Çoka çok sorgu

_via_ söz dizimini açıklamak için takma ad içeren bir sorguya bakalım.

query GetMovieCast($movieId: UUID!, $actorId: UUID!) @auth(level: PUBLIC) {
  movie(id: $movieId) {
    mainActors: actors_via_MovieActor(where: { role: { eq: "main" } }) {
      name
    }
    supportingActors: actors_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      name
    }
  }
  actor(id: $actorId) {
    mainRoles: movies_via_MovieActor(where: { role: { eq: "main" } }) {
      title
    }
    supportingRoles: movies_via_MovieActor(
      where: { role: { eq: "supporting" } }
    ) {
      title
    }
  }
}

Toplama sorguları

Toplamalar nedir ve neden kullanılır?

Toplu alanlar, bir sonuç listesi üzerinde hesaplama yapmanıza olanak tanır. Toplama alanları ile aşağıdakiler gibi işlemler yapabilirsiniz:

  • Bir yorumun ortalama puanını bulma
  • Alışveriş sepetindeki öğelerin toplam maliyetini bulma
  • En yüksek veya en düşük puan alan ürünü bulma
  • Mağazanızdaki ürün sayısını sayma

Toplamalar sunucuda gerçekleştirilir. Bu, toplama işlemlerini istemci tarafında hesaplamaya kıyasla çeşitli avantajlar sunar:

  • Daha hızlı uygulama performansı (istemci tarafı hesaplamalardan kaçındığınız için)
  • Azaltılmış veri çıkış maliyetleri (tüm girişler yerine yalnızca birleştirilmiş sonuçları gönderdiğiniz için)
  • Daha iyi güvenlik (müşterilere veri kümesinin tamamı yerine toplu verilere erişim izni verebileceğiniz için)

Toplamalar için örnek şema

Bu bölümde, toplamaların nasıl kullanılacağını açıklamak için iyi bir örnek olan bir mağaza şemalarına geçeceğiz:

  type Product @table {
    name: String!
    manufacturer: String!
    quantityInStock: Int!
    price: Float!
    expirationDate: Date
  }

Basit toplamlar

Tüm alanlar için _count

En basit toplama alanı _count'tür: Sorgunuzla eşleşen satır sayısını döndürür. Data Connect, türünüzün her bir alanı için alan türüne bağlı olarak ilgili toplu alanları oluşturur.

query CountProducts {
  products {
    _count
  }
}

Örneğin, veritabanınızda 5 ürün varsa sonuç şöyle olur:

{
  "products": [
    {
    "_count": 5
    }
  ]
}

Tüm alanların, bu alanda boş olmayan kaç satır olduğunu sayan bir <field>_count alanı vardır.

query CountProductsWithExpirationDate {
  products {
    expirationDate_count
  }
}

Örneğin, geçerlilik bitiş tarihi olan 3 ürününüz varsa sonuç şöyle olur:

{
  "products": [
    {
    "expirationDate_count": 3
    }
  ]
}
Sayısal alanlar için _min, _max, _sum ve _avg

Sayısal alanlarda (int, float, int64) da <field>_min, <field>_max, <field>_sum ve <field>_avg bulunur.

query NumericAggregates {
  products {
  quantityInStock_max
  price_min
  price_avg
  quantityInStock_sum
  }
}

Örneğin, aşağıdaki ürünlere sahipseniz:

  • A Ürünü: quantityInStock: 10, price: 2.99
  • B ürünü: quantityInStock: 5, price: 5.99
  • C ürünü: quantityInStock: 20, price: 1.99

Sonuç şöyle olur:

{
  "products": [
    {
    "quantityInStock_max": 20,
    "price_min": 1.99,
    "price_avg": 3.6566666666666666,
    "quantityInStock_sum": 35
    }
  ]
}
Tarihler ve zaman damgalarıyla ilgili _min ve _max

Tarih ve zaman damgası alanlarında <field>_min ve <field>_max bulunur.

query DateAndTimeAggregates {
  products {
  expirationDate_max
  expirationDate_min
  }
}

Örneğin, aşağıdaki geçerlilik bitiş tarihlerine sahipseniz:

  • A ürünü: 2024-01-01
  • Ürün B: 2024-03-01
  • C ürünü: 2024-02-01

Sonuç şöyle olur:

{
  "products": [
    {
    "expirationDate_max": "2024-03-01",
    "expirationDate_min": "2024-01-01"
    }
  ]
}

Farklı

distinct bağımsız değişkeni, bir alan (veya alan kombinasyonu) için tüm benzersiz değerleri almanıza olanak tanır. Örneğin:

query ListDistinctManufacturers {
  products(distinct: true) {
    manufacturer
  }
}

Örneğin, aşağıdaki üreticilere sahipseniz:

  • A ürünü: manufacturer: "Acme"
  • Ürün B: manufacturer: "Beta"
  • C ürünü: manufacturer: "Acme"

Sonuç şöyle olur:

{
  "products": [
    { "manufacturer": "Acme" },
    { "manufacturer": "Beta" }
  ]
}

Ayrıca, farklı değerleri toplamak için toplu alanlarda distinct bağımsız değişkenini de kullanabilirsiniz. Örneğin:

query CountDistinctManufacturers {
  products {
    manufacturer_count(distinct: true)
  }
}

Örneğin, aşağıdaki üreticilere sahipseniz:

  • A ürünü: manufacturer: "Acme"
  • Ürün B: manufacturer: "Beta"
  • C ürünü: manufacturer: "Acme"

Sonuç şöyle olur:

{
  "products": [
    {
    "manufacturer_count": 2
    }
  ]
}

Gruplandırılmış toplamalar

Bir türde toplu ve toplu olmayan alanların bir karışımını seçerek gruplandırılmış toplama işlemi gerçekleştirirsiniz. Bu işlem, toplu olmayan alanlar için aynı değere sahip tüm eşleşen satırları gruplandırır ve bu grup için toplu alanları hesaplar. Örneğin:

query MostExpensiveProductByManufacturer {
  products {
  manufacturer
  price_max
  }
}

Örneğin, aşağıdaki ürünlere sahipseniz:

  • A Ürünü: manufacturer: "Acme", price: 2.99
  • B ürünü: manufacturer: "Beta", price: 5.99
  • C ürünü: manufacturer: "Acme", price: 1.99

Sonuç şöyle olur:

{
  "products": [
    { "manufacturer": "Acme", "price_max": 2.99 },
    { "manufacturer": "Beta", "price_max": 5.99 }
  ]
}
Gruplandırılmış toplama içeren having ve where

Yalnızca belirtilen ölçütleri karşılayan grupları döndürmek için having ve where bağımsız değişkenini de kullanabilirsiniz.

  • having, grupları toplu alanlarına göre filtrelemenize olanak tanır.
  • where, satırları toplu olmayan alanlara göre filtrelemenize olanak tanır.

query FilteredMostExpensiveProductByManufacturer {
  products(having: {price_max: {ge: 2.99}}) {
  manufacturer
  price_max
  }
}

Örneğin, aşağıdaki ürünlere sahipseniz:

  • A Ürünü: manufacturer: "Acme", price: 2.99
  • B ürünü: manufacturer: "Beta", price: 5.99
  • C ürünü: manufacturer: "Acme", price: 1.99

Sonuç şöyle olur:

{
  "products": [
    { "manufacturer": "Acme", "price_max": 2.99 },
    { "manufacturer": "Beta", "price_max": 5.99 }
  ]
}

Tablolar genelinde toplanır.

Toplama alanları, verilerinizle ilgili karmaşık soruları yanıtlamak için oluşturulan bire çok ilişki alanlarıyla birlikte kullanılabilir. Aşağıda, örneklerde kullanabileceğimiz ayrı bir Manufacturer tablosu içeren değiştirilmiş bir şema verilmiştir:

  type Product @table {
    name: String!
    manufacturer: Manufacturer!
    quantityInStock: Int!
    price: Float!
    expirationDate: Date
  }

  type Manufacturer @table {
    name: String!
    headquartersCountry: String!
  }

Artık bir üreticinin kaç ürün ürettiğini bulmak gibi işlemleri yapmak için toplu alanları kullanabiliriz:

query GetProductCount($id: UUID) {
  manufacturers {
    name
    products_on_manufacturer {
      _count
    }
  }
}

Örneğin, aşağıdaki üreticilere sahipseniz:

  • A üreticisi: name: "Acme", products_on_manufacturer: 2
  • Üretici B: name: "Beta", products_on_manufacturer: 1

Sonuç şöyle olur:

{
  "manufacturers": [
    { "name": "Acme", "products_on_manufacturer": { "_count": 2 } },
    { "name": "Beta", "products_on_manufacturer": { "_count": 1 } }
  ]
}

Film eleştirisi veritabanı için mutasyonlar

Daha önce de belirtildiği gibi, şemanızda bir tablo tanımladığınızda Data Connect, her tablo için temel, gizli mutasyonlar oluşturur.

type Movie @table { ... }

extend type Mutation {
  # Insert a row into the movie table.
  movie_insert(...): Movie_Key!
  # Upsert a row into movie."
  movie_upsert(...): Movie_Key!
  # Update a row in Movie. Returns null if a row with the specified id/key does not exist
  movie_update(...): Movie_Key
  # Update rows based on a filter in Movie.
  movie_updateMany(...): Int!
  # Delete a single row in Movie. Returns null if a row with the specified id/key does not exist
  movie_delete(...): Movie_Key
  # Delete rows based on a filter in Movie.
  movie_deleteMany(...): Int!
}

Bu sayede, giderek daha karmaşık temel CRUD işlemlerini uygulayabilirsiniz. Bunu hızlıca beş kez söyle.

@transaction yönergesi

Bu yönerge, bir mutasyonun her zaman bir veritabanı işleminde çalıştırılmasını zorunlu kılar.

@transaction içeren mutasyonların tamamen başarılı veya tamamen başarısız olacağı garanti edilir. İşlemdeki alanlardan herhangi biri başarısız olursa tüm işlem geri alınır. İstemci açısından, tüm istek bir istek hatasıyla başarısız olmuş ve yürütme işlemi başlamamış gibi davranır.

@transaction içermeyen mutasyonlar, her bir kök alanı sırayla birbiri ardına yürütür. Tüm hataları kısmi alan hataları olarak gösterir ancak sonraki yürütmelerin etkilerini göstermez.

Oluştur

Temel oluşturma işlemlerini yapalım.

# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
  movie_insert(data: {
    title: $title
    releaseYear: $releaseYear
    genre: $genre
    rating: $rating
  })
}

# Create a movie with default values
mutation CreateMovie2 {
  movie_insert(data: {
    title: "Sherlock Holmes"
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
  })
}

Veya bir upsert.

# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
  movie_upsert(data: {
    title: $title
    releaseYear: 2009
    genre: "Mystery"
    rating: 5
    genre: "Mystery/Thriller"
  })
}

Güncelleme yapma

Güncellemeleri aşağıda bulabilirsiniz. Yapımcılar ve yönetmenler, bu ortalama puanların trende uygun olmasını ister.

movie_update alanı, bir kaydı tanımlamak için beklenen bir id bağımsız değişkeni ve bu güncellemede değerleri ayarlamak için kullanabileceğiniz bir data alanı içerir.

mutation UpdateMovie(
  $id: UUID!,
  $genre: String!,
  $rating: Int!,
  $description: String!
) {
  movie_update(id: $id,
    data: {
      genre: $genre
      rating: $rating
      description: $description
    })
}

Birden fazla güncelleme yapmak için movie_updateMany alanını kullanın.

# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $rating: Int!) {
  movie_updateMany(
    where: { genre: { eq: $genre } },
    data:
      {
        rating: $rating
      })
}

_update ile artma, azalma, ekleme ve önce ekleme işlemlerini kullanma

_update ve _updateMany mutasyonlarında data:'de değerleri açıkça ayarlayabilirsiniz ancak değerleri güncellemek için genellikle artma gibi bir operatör uygulamak daha mantıklı olur.

Önceki güncelleme örneğini değiştirmek için belirli bir filmin puanını artırmak istediğinizi varsayalım. rating_update söz dizimini inc operatörüyle kullanabilirsiniz.

mutation UpdateMovie(
  $id: UUID!,
  $ratingIncrement: Int!
) {
  movie_update(id: $id, data: {
    rating_update: {
      inc: $ratingIncrement
    }
  })
}

Data Connect, alan güncellemeleri için aşağıdaki operatörleri destekler:

  • Int, Int64 ve Float veri türlerini artırmak için inc
  • Int, Int64 ve Float veri türlerini azaltmak için dec
  • Vektör listeleri hariç liste türlerine eklemek için append
  • Vektör listeleri hariç liste türlerine ön ek olarak eklenmek için prepend

Silme işlemleri gerçekleştirme

Film verilerini silebilirsiniz. Film koruma uzmanları, fiziksel filmlerin mümkün olduğunca uzun süre korunmasını ister.

# Delete by key
mutation DeleteMovie($id: UUID!) {
  movie_delete(id: $id)
}

Burada _deleteMany kullanabilirsiniz.

# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
  movie_deleteMany(where: { rating: { le: $minRating } })
}

İlişkilerde mutasyon yazma

Bir ilişkide örtülü _upsert mutasyonunun nasıl kullanıldığını gözlemleyin.

# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
  movieMetadata_upsert(
    data: { movie: { id: $movieId }, director: $director }
  )
}

Data Connect'ün field_expr söz dizimini kullanarak değer sağlamasına izin verin

Anahtar skaler ve sunucu değerleri bölümünde belirtildiği gibi, şemanızı, sunucunun istemci isteklerine yanıt olarak id ve tarihler gibi ortak alanlar için değerleri dolduracağı şekilde tasarlayabilirsiniz.

Ayrıca, istemci uygulamalarından Data Connect request nesnelerinde gönderilen kullanıcı kimlikleri gibi verilerden yararlanabilirsiniz.

Mutasyonlar uygularken sunucu tarafından oluşturulan güncellemeleri tetiklemek veya isteklerdeki verilere erişmek için field_expr söz dizimini kullanın. Örneğin, bir istekte saklanan uid yetkilendirmesini bir _upsert işlemine iletmek için userId_expr alanına "auth.uid" değerini iletin.

# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}

# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
  favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}

Alternatif olarak, tanıdık bir yapılacaklar listesi uygulamasında yeni bir yapılacaklar listesi oluştururken id_expr değerini ileterek sunucunun liste için otomatik olarak bir UUID oluşturmasını sağlayabilirsiniz.

mutation CreateTodoListWithFirstItem(
  $listName: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
    name: $listName,
  })
}

Daha fazla bilgi için skalar referansında _Expr skalarlarına bakın.

Yetkilendirme verisi arama sorguları

Data Connect mutasyonları, önce veritabanını sorgulayarak ve sorgunun sonuçlarını CEL ifadeleriyle doğrulayarak yetkilendirilebilir. Bu, örneğin bir tabloya yazarken başka bir tablodaki bir satırın içeriğini kontrol etmeniz gerektiğinde kullanışlıdır.

Bu özellik şunları destekler:

  • Alanların içeriğini değerlendirmenize ve bu değerlendirmenin sonuçlarına göre işlem yapmanıza olanak tanıyan @check yönergesi:
    • Bir mutasyonla tanımlanan oluşturma, güncelleme ve silme işlemlerine devam edin
    • Sorgu sonuçlarını döndürmeye devam edin
    • Müşteri kodunuzda farklı mantıklar yürütmek için döndürülen değerleri kullanma
  • Sorgu sonuçlarını kablo protokolü sonuçlarından çıkarmanıza olanak tanıyan @redact yönergesi.

Bu özellikler yetkilendirme akışları için yararlıdır.

Eşdeğer SQL şeması

-- Movies Table
CREATE TABLE Movies (
    movie_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INT,
    genre VARCHAR(30),
    rating INT,
    description TEXT,
    tags TEXT[]
);
-- Movie Metadata Table
CREATE TABLE MovieMetadata (
    movie_id UUID REFERENCES Movies(movie_id) UNIQUE,
    director VARCHAR(255) NOT NULL,
    PRIMARY KEY (movie_id)
);
-- Actors Table
CREATE TABLE Actors (
    actor_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    name VARCHAR(30) NOT NULL
);
-- MovieActor Join Table for Many-to-Many Relationship
CREATE TABLE MovieActor (
    movie_id UUID REFERENCES Movies(movie_id),
    actor_id UUID REFERENCES Actors(actor_id),
    role VARCHAR(50) NOT NULL, # "main" or "supporting"
    PRIMARY KEY (movie_id, actor_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id),
    FOREIGN KEY (actor_id) REFERENCES Actors(actor_id)
);
-- Users Table
CREATE TABLE Users (
    user_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_auth VARCHAR(255) NOT NULL
    username VARCHAR(30) NOT NULL
);
-- Reviews Table
CREATE TABLE Reviews (
    review_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_id UUID REFERENCES Users(user_id),
    movie_id UUID REFERENCES Movies(movie_id),
    rating INT,
    review_text TEXT,
    review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (movie_id, user_id)
    FOREIGN KEY (user_id) REFERENCES Users(user_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
-- Self Join Example for Movie Sequel Relationship
ALTER TABLE Movies
ADD COLUMN sequel_to UUID REFERENCES Movies(movie_id);

Sırada ne var?