如何在 Prisma 2 中使用“计数”和“分组依据”?

Posted

技术标签:

【中文标题】如何在 Prisma 2 中使用“计数”和“分组依据”?【英文标题】:How can I use "count" and "group by" in Prisma 2? 【发布时间】:2020-08-18 08:33:40 【问题描述】:

我有这个有效的功能:

export const tagsByLabel = async (params) => 
  const findManyParams = 
    where:  userId: userIdFromSession ,
    orderBy:  title: "asc" ,
  ;
  if (params) 
    const  searchTerm  = params;
    findManyParams.where.title =  contains: searchTerm ;
  
  console.log("findManyParams", findManyParams);
  const tagsByLabelResult = await db.tag.findMany(findManyParams);
  console.log("tagsByLabelResult", tagsByLabelResult);
  return tagsByLabelResult;
;

如果我搜索“mex”,我会看到:

    findManyParams 
      where:  userId: 1, title:  contains: 'mex'  ,
      orderBy:  title: 'asc' 
    
    tagsByLabelResult [
      
        id: 9,
        title: 'mex',
        description: 'Mexican food',
        userId: 1,
        createdAt: 2020-05-03T22:16:09.134Z,
        modifiedAt: 2020-05-03T22:16:09.134Z
      
    ]

对于空查询,tagsByLabelResult 包含所有标签记录。

如何调整我的tagsByLabel 函数以聚合(使用“分组依据”)记录并按计数降序为tagsByLabelResult 的每条记录输出一个“计数”?

    tagsByLabelResult [
      
        id: 9,
        title: 'mex',
        description: 'Mexican food',
        count: 25,
        userId: 1,
        createdAt: 2020-05-03T22:16:09.134Z,
        modifiedAt: 2020-05-03T22:16:09.134Z
      
    ]

我看到prisma.user.count() 的docs example,但这似乎检索了整个查询结果的简单计数,而不是作为具有“分组依据”的字段的计数。

我正在使用 RedwoodJs、Prisma 2、Apollo、GraphQL。

【问题讨论】:

【参考方案1】:

到目前为止,groupBy 支持仍在规范中,here 因此目前您只能在特定查询中使用count

作为一种解决方法,您暂时必须使用prisma.raw

【讨论】:

好的,我去看看prisma.io/docs/reference/tools-and-interfaces/prisma-client/…。谢谢。【参考方案2】:

在我的tags.sdl.js 我需要添加:

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

并将查询 tagsByLabel(searchTerm: String): [Tag!]! 更改为 tagsByLabel(searchTerm: String): [TagCount!]!

在我的TagsAutocomplete.js 组件中,我现在有:

export const TagsAutocomplete = ( onChange, selectedOptions, closeMenuOnSelect ) => 
  const state = 
    isLoading: false,
  ;

  const client = useApolloClient();

  const promiseOptions = useCallback(
    async (searchTerm) => 
      try 
        const  data  = await client.query(
          query: QUERY_TAGS_BY_LABEL,
          variables:  searchTerm ,
        );

        console.log("promiseOptions data", data);
        const tags = data.tags.map((tag) => 
          if (!tag.label.includes("(")) 
            //ONEDAY why does the count keep getting appended if this condition isn't checked here?
            tag.label = tag.label + " (" + tag.count + ")";
          
          return tag;
        );
        console.log("promiseOptions tags", tags);
        return tags;
       catch (e) 
        console.error("Error fetching tags", e);
      
    ,
    [client]
  );
;

在我的tags.js 服务中,我现在拥有:

export const tagsByLabel = async (params) => 
  let query = `
      SELECT t.*, COUNT(pt.B) as count FROM tag t LEFT JOIN _PrincipleToTag pt ON t.id = pt.B WHERE t.userId = $userIdFromSession `;

  if (params) 
    const  searchTerm  = params;
    if (searchTerm) 
      query += `AND t.title LIKE '%$searchTerm%' `;
    
  
  query += "GROUP BY t.id ORDER BY count DESC, t.title ASC;";
  console.log("query", query);
  const tagsByLabelResult = await db.raw(query);
  //TODO get secure parameterization working
  console.log("tagsByLabelResult", tagsByLabelResult);
  return tagsByLabelResult;
;

但是,正如评论中提到的,我仍在试图弄清楚如何让secure parameterization 工作。

【讨论】:

嗨@Ryan,您可能已经知道如何安全地参数化,但如果您还没有,我会这样做。基于:prisma.io/docs/reference/tools-and-interfaces/prisma-client/… 我设法让它在这里工作:gist.github.com/Aidurber/a8c9b97b994fa4a0e46a9243ba378a79 这真的很丑,我找不到一个干净的抽象来使它更通用一点,但它可以解决问题。 @ZeroBased_IX 感谢您的留言;我会检查一下。

以上是关于如何在 Prisma 2 中使用“计数”和“分组依据”?的主要内容,如果未能解决你的问题,请参考以下文章

Prisma:如何找到与 id 列表匹配的所有元素?

如何在 Docker 中使用 Prisma 2

如何使用 prisma 2 或 3 和 nexus 模式生成同时生成生成的 crud 和“ondelete 级联”

如何在 prisma 中使用 connectOrCreate 与多对多

如何在 docker 容器中连接 graphql 和 prisma?

如何在 prisma 中使用 findUnique 和 post id 和 prodCode 来查找帖子