طرحواره ها، پرس و جوها و جهش های اتصال داده

Firebase Data Connect به شما امکان می دهد برای نمونه های PostgreSQL خود که با Google Cloud SQL مدیریت می شوند، رابط ایجاد کنید. این رابط‌ها ترکیبی از طرح‌واره، پرسش‌ها و جهش‌ها برای استفاده از داده‌های شما هستند.

راهنمای شروع یک طرح برنامه بررسی فیلم را برای PostgreSQL معرفی کرد و این راهنما نگاهی عمیق تر به نحوه طراحی طرحواره های Data Connect برای PostgreSQL دارد.

این راهنما پرس و جوها و جهش های Data Connect را با نمونه های طرحواره جفت می کند. چرا پرس و جوهاجهش ها ) را در راهنمای طرحواره های Data Connect مورد بحث قرار می دهیم؟ مانند سایر پلتفرم‌های مبتنی بر GraphQL، Firebase Data Connect یک پلتفرم توسعه اولین پرس و جو است، بنابراین به‌عنوان یک توسعه‌دهنده، در مدل‌سازی داده‌های خود به داده‌هایی فکر می‌کنید که مشتریانتان به آن نیاز دارند، که تا حد زیادی بر طرح داده‌ای که برای پروژه خود ایجاد می‌کنید، تأثیر می‌گذارد.

این راهنما با طرحی جدید برای بررسی فیلم شروع می‌شود، سپس پرسش‌ها و جهش‌های حاصل از آن طرح را پوشش می‌دهد و در نهایت فهرستی از SQL معادل طرح اصلی Data Connect ارائه می‌دهد.

طرحی برای یک برنامه بررسی فیلم

تصور کنید می خواهید سرویسی بسازید که به کاربران اجازه می دهد نظرات فیلم ها را ارسال و مشاهده کنند.

برای چنین اپلیکیشنی به یک طرح اولیه نیاز دارید. بعداً این طرح را برای ایجاد پرس و جوهای رابطه ای پیچیده گسترش خواهید داد.

میز فیلم

طرح فیلم ها حاوی دستورالعمل های اصلی مانند:

  • @table(name) و @col(name) برای سفارشی کردن جدول SQL و نام ستون. Data Connect نام‌های snake_case را در صورت عدم مشخص کردن ایجاد می‌کند.
  • @col(dataType) برای سفارشی کردن انواع ستون SQL.
  • @default برای پیکربندی مقادیر پیش‌فرض ستون SQL در حین درج.

برای جزئیات بیشتر، اسناد مرجع برای @table ، @col ، @default را بررسی کنید.

# 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
}

اسکالرهای کلیدی و مقادیر سرور

قبل از بررسی بیشتر برنامه بررسی فیلم، اجازه دهید اسکالرهای کلید Data Connect و مقادیر سرور را معرفی کنیم.

اسکالرهای کلیدی شناسه های شی مختصر هستند که Data Connect به طور خودکار از فیلدهای کلیدی در طرحواره های شما جمع آوری می کند. اسکالرهای کلیدی در مورد کارایی هستند و به شما امکان می دهند در یک تماس اطلاعاتی درباره هویت و ساختار داده های خود پیدا کنید. آنها به ویژه زمانی مفید هستند که می خواهید اقدامات متوالی را روی رکوردهای جدید انجام دهید و به یک شناسه منحصر به فرد برای ارسال به عملیات آینده نیاز دارید، و همچنین زمانی که می خواهید به کلیدهای رابطه ای برای انجام عملیات پیچیده تر اضافی دسترسی داشته باشید.

با استفاده از مقادیر سرور ، می توانید به طور موثر به سرور اجازه دهید فیلدهای جداول شما را با استفاده از مقادیر ذخیره شده یا قابل محاسبه بر اساس عبارات خاص CEL سمت سرور در آرگومان expr به صورت پویا پر کند. به عنوان مثال، می‌توانید فیلدی را تعریف کنید که وقتی به فیلد با استفاده از زمان ذخیره‌شده در یک درخواست عملیات دسترسی داده می‌شود، یک مهر زمانی اعمال می‌شود updatedAt: Timestamp! @default(expr: "request.time") .

جدول فراداده فیلم

اکنون بیایید کارگردانان فیلم را ردیابی کنیم و همچنین یک رابطه یک به یک با Movie برقرار کنیم.

فیلد مرجع را برای تعریف یک رابطه اضافه کنید.

می توانید از دستور @ref برای سفارشی کردن محدودیت کلید خارجی استفاده کنید.

  • @ref(fields) برای تعیین فیلدهای کلید خارجی.
  • @ref(references) برای تعیین فیلدهای ارجاع شده در جدول هدف. این مرجع به طور پیش فرض کلید اصلی است، اما فیلدهای با @unique نیز پشتیبانی می شوند.

برای جزئیات بیشتر، اسناد مرجع برای @ref را بررسی کنید.

# 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
}

بازیگر و بازیگر سینما

در مرحله بعد، شما می خواهید بازیگران در فیلم های شما بازی کنند، و از آنجایی که بین فیلم ها و بازیگران رابطه چند به چند دارید، یک جدول پیوستن ایجاد کنید.

# 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
}

کاربر

در نهایت، کاربران برای برنامه شما.

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

انواع داده های پشتیبانی شده

Data Connect از انواع داده های اسکالر زیر پشتیبانی می کند، با انتساب به انواع PostgreSQL با استفاده از @col(dataType:) .

نوع Data Connect GraphQL توکار نوع یا
نوع سفارشی Data Connect
نوع پیش فرض PostgreSQL پشتیبانی از انواع PostgreSQL
(نام مستعار داخل پرانتز)
رشته GraphQL متن متن
بیت (n)، varbit (n)
char(n)، varchar(n)
بین المللی GraphQL بین المللی Int2 (کوچک، سریال کوچک)،
int4 (عدد صحیح، int، سریال)
شناور GraphQL شناور8 float4 (واقعی)
float8 (دقت دوگانه)
عددی (اعشاری)
بولی GraphQL بولی بولی
UUID سفارشی uuid uuid
Int64 سفارشی bigint int8 (bigint، bigserial)
عددی (اعشاری)
تاریخ سفارشی تاریخ تاریخ
مهر زمان سفارشی timestamptz

timestamptz

توجه: اطلاعات منطقه زمانی محلی ذخیره نمی شود.
PostgreSQL مُهرهای زمانی مانند UTC را تبدیل و ذخیره می کند.

بردار سفارشی بردار

بردار

به انجام جستجوی شباهت برداری با Vertex AI مراجعه کنید.

  • GraphQL List به یک آرایه یک بعدی نگاشت می شود.
    • برای مثال، [Int] به int5[] , [Any] به jsonb[] نقشه می‌دهد.
    • Data Connect از آرایه های تو در تو پشتیبانی نمی کند.

از فیلدهای ایجاد شده برای ساخت پرس و جو و جهش استفاده کنید

جستارها و جهش های Data Connect شما مجموعه ای از فیلدها را گسترش می دهد که به طور خودکار Data Connect را بر اساس انواع و روابط نوع در طرح شما ایجاد می کند. هر زمان که شما طرحواره خود را ویرایش می کنید، این فیلدها توسط ابزارهای محلی ایجاد می شوند.

  • همانطور که در راهنمای شروع کشف کردید، کنسول Firebase و ابزار توسعه محلی ما از این فیلدهای تولید شده به صورت خودکار برای ارائه درخواست‌ها و جهش‌های اداری موقتی استفاده می‌کنند که می‌توانید از آنها برای تخمین داده‌ها و تأیید محتویات جداول خود استفاده کنید.

  • در فرآیند توسعه خود، پرس و جوهای قابل استقرار و جهش‌های قابل استقرار را که در کانکتورهای خود بسته‌بندی شده‌اند، بر اساس این فیلدهای تولید شده خودکار پیاده‌سازی خواهید کرد.

نامگذاری فیلد به صورت خودکار

Data Connect نام‌های مناسبی را برای فیلدهایی که به طور خودکار بر اساس اعلان‌های نوع طرح شما ایجاد می‌شوند استنباط می‌کند. به عنوان مثال، کار با یک منبع PostgreSQL، اگر جدولی به نام Movie تعریف کنید، سرور تولید می کند:

  • فیلدها برای خواندن داده‌ها در جدول تک از مواردی با نام‌های دوستانه movie (مفرد، برای بازیابی نتایج فردی با عبور ارگ‌هایی مانند eq ) و movies (جمع، برای بازیابی فهرست‌های نتایج با ارسال آرگومان‌هایی مانند gt و عملیاتی مانند orderby ) استفاده می‌کنند. Data Connect همچنین فیلدهایی را برای عملیات چند جدولی و رابطه‌ای با نام‌های صریح مانند actors_on_movies یا actors_via_actormovie ایجاد می‌کند.
  • فیلدهایی برای نوشتن داده با نام آشنا مانند movie_insert ، movie_upsert ...

زبان تعریف طرحواره همچنین به شما این امکان را می دهد که به طور صریح نحوه تولید نام برای فیلدها را با استفاده از آرگومان های دستوری singular و plural کنترل کنید.

دستورالعمل برای پرس و جو و جهش

علاوه بر دستورالعمل‌هایی که در تعریف انواع و جداول استفاده می‌کنید، Data Connect دستورات @auth ، @check ، @redact و @transaction را برای تقویت رفتار کوئری‌ها و جهش‌ها ارائه می‌کند.

بخشنامه قابل اجرا برای توضیحات
@auth پرس و جو و جهش خط مشی احراز هویت را برای یک پرس و جو یا جهش تعریف می کند. راهنمای مجوز و گواهینامه را ببینید.
@check درخواست جستجوی داده های مجوز بررسی می کند که فیلدهای مشخص شده در نتایج پرس و جو وجود دارد. یک عبارت Common Expression Language (CEL) برای آزمایش مقادیر فیلد استفاده می شود. راهنمای مجوز و گواهینامه را ببینید.
@redact پرس و جوها بخشی از پاسخ مشتری را ویرایش می کند. راهنمای مجوز و گواهینامه را ببینید.
@transaction جهش ها الزام می کند که یک جهش همیشه در یک تراکنش پایگاه داده اجرا شود. نمونه های جهش برنامه فیلم را ببینید.

پرس و جو برای پایگاه داده نقد و بررسی فیلم

شما یک کوئری Data Connect را با اعلان نوع عملیات پرس و جو، نام عملیات، آرگومان های عملیات صفر یا بیشتر، و صفر یا بیشتر دستورالعمل با آرگومان ها تعریف می کنید.

در شروع سریع، پرس و جوی مثال listEmails هیچ پارامتری نداشت. البته در بسیاری از موارد داده های ارسال شده به فیلدهای پرس و جو پویا خواهند بود. می‌توانید از نحو $variableName برای کار با متغیرها به‌عنوان یکی از اجزای تعریف پرس‌وجو استفاده کنید.

بنابراین پرس و جو زیر دارد:

  • تعریف نوع query
  • نام عملیات ListMoviesByGenre (پرس و جو).
  • یک آرگومان عملیات $genre متغییر
  • یک دستورالعمل واحد، @auth .
query ListMoviesByGenre($genre: String!) @auth(level: USER)

هر آرگومان پرس و جو نیاز به یک اعلان نوع، یک نوع داخلی مانند String ، یا یک نوع سفارشی، طرحواره تعریف شده مانند Movie دارد.

بیایید به امضای پرس و جوهای پیچیده تر نگاه کنیم. با معرفی عبارات روابط قدرتمند و مختصر که می‌توانید برای ایجاد پرس و جوهای قابل استقرار خود از آنها استفاده کنید، پایان می‌دهید.

اسکالرهای کلیدی در پرس و جوها

اما ابتدا یک نکته در مورد اسکالرهای کلیدی.

Data Connect نوع خاصی را برای اسکالرهای کلیدی تعریف می کند که با _Key مشخص می شود. به عنوان مثال، نوع اسکالر کلید برای جدول Movie ما Movie_Key است.

شما اسکالرهای کلیدی را به عنوان پاسخی که توسط اکثر فیلدهای خواندنی تولید شده به طور خودکار بازیابی می شود، یا البته از پرس و جوهایی که در آن همه فیلدهای مورد نیاز برای ساخت کلید اسکالر را بازیابی کرده اید، بازیابی می کنید.

پرس‌وجوهای خودکار منفرد، مانند movie در مثال در حال اجرا، از یک آرگومان کلیدی پشتیبانی می‌کنند که یک اسکالر کلیدی را می‌پذیرد.

شما ممکن است یک اسکالر کلیدی را به صورت تحت اللفظی پاس کنید. اما، می توانید متغیرهایی را برای ارسال اسکالرهای کلیدی به عنوان ورودی تعریف کنید.

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

اینها را می توان در درخواست JSON مانند این (یا سایر قالب های سریال سازی) ارائه کرد:

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

به لطف تجزیه اسکالر سفارشی، یک Movie_Key نیز می تواند با استفاده از نحو شی که ممکن است حاوی متغیرهایی باشد ساخته شود. این بیشتر زمانی مفید است که بخواهید به دلایلی اجزای جداگانه را به متغیرهای مختلف تقسیم کنید.

نام مستعار در پرس و جوها

Data Connect از نام مستعار GraphQL در کوئری ها پشتیبانی می کند. با نام مستعار، نام داده هایی را که در نتایج یک پرس و جو برگردانده می شوند، تغییر می دهید. یک کوئری Data Connect می تواند چندین فیلتر یا عملیات پرس و جوی دیگر را در یک درخواست کارآمد به سرور اعمال کند و به طور موثر چندین «پرس و جوی فرعی» را همزمان صادر کند. برای جلوگیری از تصادم نام در مجموعه داده های برگشتی، از نام مستعار برای تشخیص پرس و جوهای فرعی استفاده می کنید.

در اینجا یک جستجو وجود دارد که در آن یک عبارت از نام مستعار mostPopular استفاده می کند.

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

پرس و جوهای ساده با فیلتر

پرس و جوهای Data Connect به تمام فیلترهای رایج SQL و عملیات سفارش نگاشت می شوند.

عملگرهای where و orderBy (پرسش‌های مفرد، جمع)

تمام ردیف های منطبق از جدول (و پیوندهای تودرتو) را برمی گرداند. اگر هیچ رکوردی با فیلتر مطابقت نداشته باشد، آرایه خالی را برمی‌گرداند.

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 و offset (پرس و جوهای مفرد، جمع)

می توانید صفحه بندی را روی نتایج انجام دهید. این آرگومان‌ها پذیرفته می‌شوند اما به نتایج بازگردانده نمی‌شوند.

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

شامل زمینه های آرایه می شود

می توانید آزمایش کنید که یک فیلد آرایه شامل یک آیتم مشخص شده باشد.

# 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
  }
}

عملیات رشته و عبارات منظم

جستارهای شما می توانند از عملیات جستجو و مقایسه رشته ای معمولی از جمله عبارات منظم استفاده کنند. توجه داشته باشید برای کارایی شما چندین عملیات را در اینجا دسته بندی می کنید و آنها را با نام مستعار رفع می کنید.

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}}}) {...}
}

or و and برای فیلترهای ترکیبی

or و and برای منطق پیچیده تر استفاده کنید.

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
  }
}

پرس و جوهای پیچیده

کوئری های Data Connect می توانند به داده ها بر اساس روابط بین جداول دسترسی داشته باشند. شما می توانید از روابط شی (یک به یک) یا آرایه (یک به چند) تعریف شده در طرحواره خود برای ایجاد پرس و جوهای تودرتو، یعنی واکشی داده برای یک نوع به همراه داده های یک نوع تودرتو یا مرتبط استفاده کنید.

چنین جستارهایی از جادویی Data Connect _on_ و _via syntax در فیلدهای خواندنی تولید شده استفاده می کنند.

شما تغییراتی در طرحواره از نسخه اولیه ما ایجاد خواهید کرد.

بسیاری به یک

بیایید نظرات را به برنامه خود اضافه کنیم، با جدول Review و تغییراتی در User .

# 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")
}

پرس و جو برای خیلی به یک

حالا بیایید به یک پرس و جو نگاه کنیم، با نام مستعار، برای نشان دادن نحو _via_ .

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
    }
  }
}

یک به یک

می توانید الگو را ببینید. در زیر، این طرح برای تصویر اصلاح شده است.

# 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
}

یک به یک پرس و جو کنید

می توانید با استفاده از نحو _on_ پرس و جو کنید.

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

خیلی به خیلی ها

فیلم ها به بازیگر نیاز دارند و بازیگران به فیلم. آنها روابط بسیار زیادی دارند که می توانید با جدول پیوستن MovieActors مدل کنید.

# 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!]!
}

پرس و جو برای بسیاری از بسیاری

بیایید به یک پرس و جو با نام مستعار نگاه کنیم تا نحو _via_ را نشان دهیم.

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
    }
  }
}

پرس و جوهای تجمع

سنگدانه ها چیست و چرا از آنها استفاده می کنیم؟

فیلدهای انبوه به شما امکان می دهد محاسبات را روی لیستی از نتایج انجام دهید. با فیلدهای انبوه، می توانید کارهایی مانند:

  • میانگین امتیاز یک بررسی را پیدا کنید
  • کل هزینه اقلام موجود در یک سبد خرید را بیابید
  • محصولی با بالاترین یا کمترین امتیاز را پیدا کنید
  • تعداد محصولات موجود در فروشگاه خود را بشمارید

انباشته ها بر روی سرور انجام می شوند که مزایای زیادی را نسبت به محاسبه آنها در سمت مشتری ارائه می دهد:

  • عملکرد سریعتر برنامه (از آنجایی که از محاسبات سمت مشتری اجتناب می کنید)
  • کاهش هزینه های خروج داده ها (از آنجایی که شما فقط نتایج جمع آوری شده را به جای همه ورودی ها ارسال می کنید)
  • امنیت بهبود یافته (از آنجایی که می توانید به مشتریان به جای کل مجموعه داده ها به داده های جمع آوری شده دسترسی داشته باشید)

طرحی مثال برای مصالح

در این بخش، به طرحی مثالی از ویترین می رویم، که برای توضیح نحوه استفاده از تجمیع ها خوب است:

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

سنگدانه های ساده

_شمار برای همه فیلدها

ساده‌ترین فیلد مجموع _count است: تعداد ردیف‌هایی که با درخواست شما مطابقت دارند را برمی‌گرداند. برای هر فیلد در نوع شما، Data Connect فیلدهای انبوه مربوطه را بسته به نوع فیلد ایجاد می کند.

query CountProducts {
  products {
    _count
  }
}

به عنوان مثال، اگر شما 5 محصول در پایگاه داده خود داشته باشید، نتیجه این خواهد بود:

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

همه فیلدها دارای یک فیلد <field>_count هستند که تعداد سطرهایی که در آن فیلد دارای مقدار غیر تهی هستند را می‌شمارد.

query CountProductsWithExpirationDate {
  products {
    expirationDate_count
  }
}

به عنوان مثال، اگر 3 محصول با تاریخ انقضا دارید، نتیجه این خواهد بود:

{
  "products": [
    {
    "expirationDate_count": 3
    }
  ]
}
_min، _max، _sum و _avg برای فیلدهای عددی

فیلدهای عددی (int، float، int64) همچنین دارای <field>_min ، <field>_max ، <field>_sum و <field>_avg هستند.

query NumericAggregates {
  products {
  quantityInStock_max
  price_min
  price_avg
  quantityInStock_sum
  }
}

به عنوان مثال، اگر محصولات زیر را دارید:

  • محصول A: quantityInStock: 10 , price: 2.99
  • محصول B: quantityInStock: 5 ، price: 5.99
  • محصول C: quantityInStock: 20 , price: 1.99

نتیجه این خواهد بود:

{
  "products": [
    {
    "quantityInStock_max": 20,
    "price_min": 1.99,
    "price_avg": 3.6566666666666666,
    "quantityInStock_sum": 35
    }
  ]
}
_min و _max برای تاریخ ها و مهرهای زمانی

فیلدهای تاریخ و مهر زمان دارای <field>_min و <field>_max هستند.

query DateAndTimeAggregates {
  products {
  expirationDate_max
  expirationDate_min
  }
}

به عنوان مثال، اگر تاریخ انقضای زیر را دارید:

  • محصول A: 2024-01-01
  • محصول B: 2024-03-01
  • محصول C: 2024-02-01

نتیجه این خواهد بود:

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

متمایز

آرگومان distinct به شما امکان می دهد تمام مقادیر منحصر به فرد یک فیلد (یا ترکیبی از فیلدها) را دریافت کنید. به عنوان مثال:

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

به عنوان مثال، اگر تولید کنندگان زیر را دارید:

  • محصول A: manufacturer: "Acme"
  • محصول B: manufacturer: "Beta"
  • محصول C: manufacturer: "Acme"

نتیجه این خواهد بود:

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

همچنین می توانید از آرگومان distinct در فیلدهای انبوه استفاده کنید تا به جای آن مقادیر متمایز را جمع آوری کنید. به عنوان مثال:

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

به عنوان مثال، اگر تولید کنندگان زیر را دارید:

  • محصول A: manufacturer: "Acme"
  • محصول B: manufacturer: "Beta"
  • محصول C: manufacturer: "Acme"

نتیجه این خواهد بود:

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

مصالح گروه بندی شده

شما با انتخاب ترکیبی از فیلدهای انبوه و غیرتجمیع روی یک نوع، یک مجموعه گروه بندی شده را انجام می دهید. این همه ردیف‌های منطبق را که مقدار یکسانی برای فیلدهای غیرمجموعه دارند را با هم گروه‌بندی می‌کند و فیلدهای انبوه را برای آن گروه محاسبه می‌کند. به عنوان مثال:

query MostExpensiveProductByManufacturer {
  products {
  manufacturer
  price_max
  }
}

به عنوان مثال، اگر محصولات زیر را دارید:

  • محصول A: manufacturer: "Acme" ، price: 2.99
  • محصول B: manufacturer: "Beta" ، price: 5.99
  • محصول C: manufacturer: "Acme" price: 1.99

نتیجه این خواهد بود:

{
  "products": [
    { "manufacturer": "Acme", "price_max": 2.99 },
    { "manufacturer": "Beta", "price_max": 5.99 }
  ]
}
having و where با دانه های گروه بندی شده

همچنین می‌توانید از آرگومان having and where فقط برای برگرداندن گروه‌هایی که معیارهای ارائه شده را دارند استفاده کنید.

  • having به شما امکان می دهد گروه ها را بر اساس فیلدهای انبوه آنها فیلتر کنید
  • where به شما امکان می دهد ردیف ها را بر اساس فیلدهای غیرتجمعی فیلتر کنید.

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

به عنوان مثال، اگر محصولات زیر را دارید:

  • محصول A: manufacturer: "Acme" ، price: 2.99
  • محصول B: manufacturer: "Beta" ، price: 5.99
  • محصول C: manufacturer: "Acme" price: 1.99

نتیجه این خواهد بود:

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

مجموع در جداول

فیلدهای انبوه را می توان در هماهنگی با فیلدهای رابطه یک به چند ایجاد شده برای پاسخ به سؤالات پیچیده در مورد داده های شما استفاده کرد. در اینجا یک طرح اصلاح شده است، با جدول جداگانه، Manufacturer ، ما می توانیم در مثال ها استفاده کنیم:

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

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

اکنون می‌توانیم از فیلدهای انبوه برای انجام کارهایی مانند یافتن تعداد محصولی که سازنده تولید می‌کند استفاده کنیم:

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

به عنوان مثال، اگر تولید کنندگان زیر را دارید:

  • سازنده A: name: "Acme" , products_on_manufacturer: 2
  • سازنده B: name: "Beta" ، products_on_manufacturer: 1

نتیجه این خواهد بود:

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

جهش برای پایگاه داده نقد فیلم

همانطور که گفته شد، زمانی که جدولی را در طرحواره خود تعریف می کنید، Data Connect جهش های ضمنی اساسی را برای هر جدول ایجاد می کند.

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!
}

با استفاده از این موارد، می توانید موارد پیچیده هسته ای CRUD را پیاده سازی کنید. پنج بار سریع بگو!

دستورالعمل @transaction

این دستورالعمل الزام می کند که یک جهش همیشه در یک تراکنش پایگاه داده اجرا شود.

جهش با @transaction تضمین شده است که یا به طور کامل موفق شود یا به طور کامل شکست بخورد. اگر هر یک از فیلدهای داخل تراکنش از کار بیفتد، کل تراکنش برگردانده می شود. از نقطه نظر مشتری، هر شکست به گونه ای رفتار می کند که گویی کل درخواست با یک خطای درخواست شکست خورده است و اجرا آغاز نشده است.

جهش های بدون @transaction هر فیلد ریشه را یکی پس از دیگری به ترتیب اجرا می کنند. هر گونه خطا را به عنوان خطای میدانی جزئی نشان می دهد، اما تاثیرات اجرای بعدی را نه.

ایجاد کنید

بیایید کارهای اساسی انجام دهیم.

# 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
  })
}

یا یک تاپیک

# 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"
  })
}

به روز رسانی را انجام دهید

در اینجا به روز رسانی است. تهیه‌کنندگان و کارگردانان مطمئناً امیدوارند که این رتبه‌بندی‌های متوسط ​​رو به رشد باشد.

فیلد movie_update حاوی یک آرگومان id مورد انتظار برای شناسایی یک رکورد و یک فیلد data است که می توانید از آن برای تنظیم مقادیر در این به روز رسانی استفاده کنید.

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

برای انجام چندین به روز رسانی، از قسمت movie_updateMany استفاده کنید.

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

با استفاده از _update از عملیات افزایش، کاهش، الحاق و پیش‌پرداخت استفاده کنید

در حالی که در جهش‌های _update و _updateMany می‌توانید به‌صراحت مقادیری را در data: اغلب اعمال عملگرهایی مانند افزایش برای به‌روزرسانی مقادیر منطقی‌تر است.

برای اصلاح مثال به‌روزرسانی قبلی، فرض کنید می‌خواهید امتیاز یک فیلم خاص را افزایش دهید. می توانید از نحو rating_update با عملگر inc استفاده کنید.

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

Data Connect از اپراتورهای زیر برای به‌روزرسانی‌های میدانی پشتیبانی می‌کند:

  • inc افزایش انواع داده های Int ، Int64 و Float
  • dec تا کاهش انواع داده های Int ، Int64 و Float
  • append به افزودن به انواع لیست، به جز لیست های برداری
  • prepend به prepend به انواع لیست، به جز لیست های برداری

حذف ها را انجام دهید

البته می توانید داده های فیلم را حذف کنید. محافظان فیلم مطمئناً مایلند که فیلم‌های فیزیکی تا زمانی که ممکن است نگهداری شوند.

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

در اینجا می توانید از _deleteMany استفاده کنید.

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

جهش را روی روابط بنویسید

نحوه استفاده از جهش _upsert ضمنی را در یک رابطه مشاهده کنید.

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

اجازه دهید Data Connect مقادیر را با استفاده از نحو field_expr عرضه کند

همانطور که در اسکالرهای کلیدی و مقادیر سرور بحث شد، می‌توانید طرح‌واره خود را طوری طراحی کنید که سرور مقادیر فیلدهای رایج مانند id و تاریخ‌ها را در پاسخ به درخواست‌های مشتری پر کند.

علاوه بر این، می‌توانید از داده‌هایی مانند شناسه‌های کاربری ارسال شده در اشیاء request Data Connect از برنامه‌های مشتری استفاده کنید.

وقتی جهش‌ها را پیاده‌سازی می‌کنید، از نحو field_expr برای راه‌اندازی به‌روزرسانی‌های تولید شده توسط سرور یا دسترسی به داده‌های درخواست‌ها استفاده کنید. به عنوان مثال، برای انتقال uid مجوز ذخیره شده در یک درخواست به یک عملیات _upsert ، "auth.uid" را در قسمت userId_expr ارسال کنید.

# 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 })
}

یا در یک برنامه آشنای فهرست کارها، هنگام ایجاد یک لیست کارهای جدید، می‌توانید id_expr برای دستور دادن به سرور برای ایجاد خودکار یک UUID برای لیست ارسال کنید.

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,
  })
}

برای اطلاعات بیشتر، به اسکالرهای _Expr در مرجع اسکالرها مراجعه کنید.

درخواست جستجوی داده های مجوز

جهش های Data Connect را می توان با پرس و جو در پایگاه داده و تأیید نتایج پرس و جو با عبارات CEL مجاز کرد. این زمانی مفید است که، برای مثال، در حال نوشتن روی یک جدول هستید، و باید محتویات یک ردیف را در جدول دیگری بررسی کنید.

این ویژگی پشتیبانی می کند:

  • دستورالعمل @check ، که به شما امکان می‌دهد محتویات فیلدها را ارزیابی کنید و بر اساس نتایج چنین ارزیابی:
    • ایجاد، به روز رسانی و حذف های تعریف شده توسط یک جهش را ادامه دهید
    • برای بازگرداندن نتایج یک پرس و جو ادامه دهید
    • از مقادیر برگشتی برای اجرای منطق های مختلف در کد مشتری خود استفاده کنید
  • دستورالعمل @redact ، که به شما امکان می دهد نتایج پرس و جو را از نتایج پروتکل سیمی حذف کنید.

این ویژگی ها برای جریان های مجوز مفید هستند.

طرحواره SQL معادل

-- 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);

بعدش چی؟

  • بیاموزید که چگونه پرس و جوها و جهش های خود را با مجوز و گواهی ایمن کنید.
  • با نحوه فراخوانی پرسش‌ها و جهش‌های خود از یک وب SDK ، Android SDK ، iOS SDK و Flutter SDK که به‌طور خودکار ایجاد می‌شود، بیاموزید.