graphql.GraphQLSchema:使用啥类型的参数来获取查询以传递给 mongo db.collection.find 来解析查询

Posted

技术标签:

【中文标题】graphql.GraphQLSchema:使用啥类型的参数来获取查询以传递给 mongo db.collection.find 来解析查询【英文标题】:graphql.GraphQLSchema: what type of argument to use to grab the query to pass to mongo db.collection.find to resolve the querygraphql.GraphQLSchema:使用什么类型的参数来获取查询以传递给 mongo db.collection.find 来解析查询 【发布时间】:2021-05-01 16:26:51 【问题描述】:

我正在学习如何使用 expressexpress-graphql、**graphql、mongoose

开发 GraphQL 服务

db.collection.find 有一个可选的 query 参数,它使用查询运算符指定选择过滤器。

我想知道是否可以定义一个模式,在其中定义一个查询字段的参数,最终将其按原样传递给集合查找方法。

例如,我希望 graphql 查询:

 todosQuerable(query: title: "Andare a Novellara") 
   _id, title, completed  

回应:


  "data": 
    "todos": [
      
        "title": "Andare a Novellara",
        "completed": false
      
    ]
  

自从在 mongo 中

> db.Todo.find(title: 'Andare a Novellara')
 "_id" : ObjectId("600d95d2e506988bc4430bb7"), "title" : "Andare a Novellara", "completed" : false 

我在想这样的事情:

   todosQuerable: 
        type: new graphql.GraphQLList(TodoType),
        args: 
          query:  type: <???????????????> ,
        ,
        resolve: (source,  query ) => 
          return new Promise((resolve, reject) => 
            TODO.find(query, (err, todos) => 
              if (err) reject(err)
              else resolve(todos)
            )
          )
        
      

我做了一些尝试,但无法知道在这种情况下我应该使用哪种类型

何帮助重现问题here the source repository of my tests

请注意,这可以正常工作:

  todosByTitle: 
    type: new graphql.GraphQLList(TodoType),
    args: 
      title:  type: graphql.GraphQLString ,
    ,
    resolve: (source,  title ) => 
      return new Promise((resolve, reject) => 
        TODO.find(title: $regex: '.*' + title + '.*', $options: 'i', (err, todos) => 
          if (err) reject(err)
          else resolve(todos)
        )
      )
    
  

但我正在寻找更通用的东西:我想获取名为 query 的 graphql 字段参数并将其按原样传递给 mongo 集合查找的 query 参数。

【问题讨论】:

【参考方案1】:

所以好消息是你可以做任何你想做的事。坏消息是:

    你必须自己做 您必须添加每个可搜索字段,因此您最终可能会在此处获得 Todo 对象的两个副本。

您要查找的类型只是 自定义输入对象类型,如下所示:

请注意下面的 GraphQLInputObjectTypeGraphQLObjectType 不同。

var TodoQueryType = new graphql.GraphQLInputObjectType(
  name: 'TodoQuery',
  fields: function () 
    return 
      _id: 
        type: graphql.GraphQLID
      ,
      title: 
        type: graphql.GraphQLString
      ,
      completed: 
        type: graphql.GraphQLBoolean
      
    
  
);
      todosQuerable: 
        ...
        type: new graphql.GraphQLList(TodoType),
        ...
        args: 
          query:  type: TodoQueryType ,
        ,
        ...
      

这两个查询效果很好!

(这是我使用别名,所以我可以一次调用两次相同的查询)


  titleSearch: todosQuerable(query: title:"Buy orange" ) 
    _id
    title
    completed
  
  idSearch: todosQuerable(query: _id:"601c3f374b6dcc601890048d" ) 
    _id
    title
    completed
  

脚注

简单地说,这通常是 GraphQL 反模式,因为这是根据您的数据库选择构建 API,而不是作为客户端驱动的 API。

按要求进行正则表达式编辑:

如果您尝试进行正则表达式查找,则必须弄清楚如何以编程方式将字符串转换为正则表达式。即您的输入是 string ("/Novellara/"),但 mongoose 需要传递 RegExp 才能使用通配符(/Novellara/,没有引号)。

您可以通过多种方式做到这一点,但我将展示一个示例。如果您将输入字段更改为使用 value 和 isExpression 的两个属性,如下所示,您可以这样做,但您必须专门制作您的查询,因为它不再只是一个传递。

var ExpressableStringInput = new graphql.GraphQLInputObjectType(
  name: 'ExpressableString',
  fields: 
    value: 
      type: graphql.GraphQLString
    ,
    isExpression:
      type: graphql.GraphQLBoolean,
      defaultValue: false,
    
  
)

var TodoQueryType = new graphql.GraphQLInputObjectType(
  name: 'TodoQuery',
  fields: function () 
    return 
      _id: 
        type: graphql.GraphQLID
      ,
      title: 
        type: ExpressableStringInput
      ,
      completed: 
        type: graphql.GraphQLBoolean
      
    
  
);

// resolver
      todosQuerable: 
        type: new graphql.GraphQLList(TodoType),
        args: 
          query:  type: TodoQueryType ,
        ,
        resolve: async (source,  query ) => 
          const dbQuery = ;

          if (query.title.isExpression) 
            dbQuery.title = new RegExp(query.title.value);
           else 
            dbQuery.title = query.title.value;
          

          return new Promise((resolve, reject) => 
            TODO.find(dbQuery, (err, todos) => 
              if (err) reject(err)
              else resolve(todos)
            )
          )
        
      

您的查询将如下所示

query 
  todosQuerable(query: title:  value: "Buy.*", isExpression: true ) 
    _id
    title
    completed
  

这个查询在我看来是有道理的。如果我考虑您将向用户显示的表单,可能会有一个输入框和一个复选框,上面写着“这是一个正则表达式吗?”或其他东西,它将填充此查询。

或者,你可以做类似的字符串匹配:如果第一个和最后一个字符是“/”,你会在将它传递给猫鼬之前自动将它变成一个正则表达式。

【讨论】:

感谢您的回答,这在大多数情况下都有效,但我仍然无法弄清楚如何传递 like 查询,例如:"title": /Novellara/,它适用于mongo &gt; db.Todo.find("title": /Novellara/) 或类似形式的查询,请参阅 ***.com/q/3305561/1657028 示例。如果您对此有任何考虑,请把它整合到答案中 另见:github.com/rondinif/lab05-mongodb-graphql/commit/… 添加了请求的正则表达式实现 伟大的更新!,现在我对如何在 graphql 中定义查询类型有了更好的理解。非常感谢您。示例代码仓库已更新:github.com/rondinif/lab05-mongodb-graphql/commit/…

以上是关于graphql.GraphQLSchema:使用啥类型的参数来获取查询以传递给 mongo db.collection.find 来解析查询的主要内容,如果未能解决你的问题,请参考以下文章

Flutter 中 required 和 @required 有啥区别。它们之间有啥区别,我们啥时候需要使用它们?

c#啥时候应该使用List,啥时候应该使用arraylist?

你啥时候把 Javascript 放在 body 里,啥时候放在 head 里,啥时候使用 doc.load? [复制]

我啥时候使用 ,啥时候不在 JavaScript 中导入 [重复]

typeof 和 instanceof 有啥区别,啥时候应该使用另一个?

C++ 标准库 - 我应该啥时候使用它,啥时候不应该使用它?