Запрос Prisma 2 для возврата только тех записей, которые связаны со ВСЕМИ предоставленными идентификаторами тегов

У меня есть таблицы Principles и Tags. И между ними существует связь "многие ко многим" (неявно соединенные).

Без использования prisma.raw, как я могу выполнить следующий запрос?

SELECT p.id, p.title, p.description, p.createdAt, p.modifiedAt
    FROM principle p
   WHERE EXISTS (SELECT NULL
                   FROM _PrincipleToTag pt
                  WHERE pt.B IN (${tagIds.join(',')})
                    AND pt.A = p.id
               GROUP BY pt.A
                 HAVING COUNT(DISTINCT pt.B) = ${tagIds.length})

Как я могу обновить этот запрос Prisma 2, чтобы возвращаемые принципы были только принципами, которые связаны со ВСЕМИ предоставленными идентификаторами тегов?

export const principles = ({ tagIds }) => {
  const payload = {
    where: {
      //TODO filter based on tagIds
    },
  }
  return db.principle.findMany(payload)
}

В документах упоминаетсяcontains а также in а также every, но я не могу найти примеры того, что пытаюсь сделать.

Я использую RedwoodJs, Prisma 2, Apollo, GraphQL.


Обновление в ответ на комментарий: вот SDL:

input CreatePrincipleInput {
  title: String!
  description: String
}

input CreatePrincipleWithTagsInput {
  title: String!
  description: String
  tagIdsJson: String
}

input CreateTagInput {
  title: String!
  description: String
}

# A date string, such as 2007-12-03, compliant with the `full-date` format
# outlined in section 5.6 of the RFC 3339 profile of the ISO 8601 standard for
# representation of dates and times using the Gregorian calendar.
scalar Date

# A date-time string at UTC, such as 2007-12-03T10:15:30Z, compliant with the
# `date-time` format outlined in section 5.6 of the RFC 3339 profile of the ISO
# 8601 standard for representation of dates and times using the Gregorian calendar.
scalar DateTime

type Mutation {
  createPrinciple(input: CreatePrincipleInput!): Principle
  createPrincipleWithTags(input: CreatePrincipleWithTagsInput!): Principle
  updatePrinciple(id: Int!, input: UpdatePrincipleInput!): Principle!
  deletePrinciple(id: Int!): Principle!
  createTag(input: CreateTagInput!): Tag!
  updateTag(id: Int!, input: UpdateTagInput!): Tag!
  deleteTag(id: Int!): Tag!
}

type Principle {
  id: Int!
  title: String!
  description: String!
  tags: [Tag]
  createdAt: DateTime!
  modifiedAt: DateTime!
}

type Query {
  redwood: Redwood
  principles(searchQuery: String, tagIds: [Int]): [Principle!]!
  tags: [Tag!]!
  tagsByLabel(searchTerm: String): [TagCount!]!
  tag(id: Int!): Tag!
}

type Redwood {
  version: String
}

type Tag {
  id: Int!
  title: String!
  principles: [Principle]
  description: String
  createdAt: DateTime!
  modifiedAt: DateTime!
}

type TagCount {
  id: Int!
  title: String!
  count: Int!
  principles: [Principle]
  description: String
  createdAt: DateTime!
  modifiedAt: DateTime!
}

# A time string at UTC, such as 10:15:30Z, compliant with the `full-time` format
# outlined in section 5.6 of the RFC 3339profile of the ISO 8601 standard for
# representation of dates and times using the Gregorian calendar.
scalar Time

input UpdatePrincipleInput {
  title: String
  description: String
}

input UpdateTagInput {
  title: String
  description: String
}

3 ответа

Решение

Не похоже, что вы используете Prisma 2. Prisma 2 использует модели (не типы) и имеет массивы, классифицированные как Principles[] vs [Principles]. Возможно, Redwood выполняет преобразование (никогда не использовал его).

Я создал вашу модель в Prisma 2 и использовал следующую команду, чтобы получить единый принцип, с которым связаны два тега. Имейте в виду, что идентификаторы взяты из моего тестового набора данных. Надеюсь, вы сможете изменить это в своем коде. Если нет, создайте песочницу / площадку с минимальным кодом для тестирования.

export const principles = async ({ searchQuery, tagIds }) => {      
  const payload = {
    where: {
      OR: [
        { title: { contains: searchQuery } },
        { description: { contains: searchQuery } },
      ],
      userId: userIdFromSession,
    },
  }
  if (tagIds.length) {
    const whereAnd = []
    tagIds.forEach((tagId) => {
      whereAnd.push({
        tags: { some: { id: tagId } },
      })
    })
    payload.where.AND = whereAnd
  }
  const result = await db.principle.findMany(payload)
  return result
}

Вы можете попробовать что-то вроде этого

export const principles = ({ searchQuery, tagIds }) => {
  const payload = {
    where: {
      OR: [
        { title: { contains: searchQuery } },
        { description: { contains: searchQuery } },
      ],
      // using the `in` operator like this
      tagId: { in: tagIds },
      userId: userIdFromSession,
    },
  }
  console.log('db.principle.findMany(payload)', payload)
  return db.principle.findMany(payload)
}

Это должно делать свое дело!

Мне пришлось прибегнуть к использованиюANDдля чего-то подобного - надеюсь, это поможет!

      const tagIds = [9,6];

where: {
  // ...
  AND: tagIds.map(tagId => ({
    tags: {
      some: {
        id: {
          equals: tagId,
        },
      },
    },
  })),
}
Другие вопросы по тегам