Prisma 2 query to return records only that are associated with ALL of the provided tag IDs

和自甴很熟 提交于 2021-01-04 03:25:17

问题


I have tables Principles and Tags. And there is a many-to-many relation between them (joined implicitly).

Without using prisma.raw, how can I run the following query?

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

How can I update this Prisma 2 query such that the principles returned are only principles that are associated with ALL of the provided tagIds?

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

The docs mention contains and in and every, but I can't find examples of what I'm trying to do.

I'm using RedwoodJs, Prisma 2, Apollo, GraphQL.


Update in response to comment: here is the 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
}

回答1:


It doesn't look like you are using prisma 2. Prisma 2 uses models (not types) and has arrays classified like Principles[] vs [Principles]. Maybe Redwood does the conversion(Never used it).

I created your model in Prisma 2 and used the following command to get a single principle that has the two tags associated with it. Keep in mind the IDs in there are from my test dataset. Hopefully, you can modify this to your code. If not, please create a sandbox/playground with minimal code for us to test.

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
}



回答2:


You could try something like this

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

That should do the trick!



来源:https://stackoverflow.com/questions/61583460/prisma-2-query-to-return-records-only-that-are-associated-with-all-of-the-provid

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!