最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to design the following resolver for GraphQL server? - Stack Overflow

programmeradmin1浏览0评论

I am using react-apollo on meteor with mysql and sequelize, I am still a beginner in JS. Lets assume I have the following resolver function on my apollo-server:

 export default resolvers = {
     Query: {
         posts(_, args){
             return Post.findAndCountAll({ where: args   });
         },
         numberOfPosts(){
             return /// the number of selected posts
         }
     }

I would like to select some data from the database where some conditions are met and then count the amount of selected rows and return them in the field "numberOfPosts". findAndCountAll() returns an object, which contains the selected rows and the count. I would like to get my post() to return only the selected rows, and my numberOfPosts() to return only the count of the selected posts. Right now, both is returned by posts().

My schema is:

 type Post {
  id: Int
  date: Float
  text: String
}

 type NumberOfPosts{
  total: Int
  filtered: Int
}

type Query {
  posts(
   id: Ind,
   offset: Int,
   limit: Int,
   filter: String): [Post]
  numberOfPosts:[NumberOfPosts] 
}

schema {
  query: Query
}

The Goal is to receive data in the following format:

{
  "data": {
    "numberOfPosts": [
      {
        "total": 1000,
        "filtered": 21
      }
    ],
    "posts": [
      {
        "id": 4,
        "date": 5105626122,
        "text": "jzybiwutudi"
      },
      ...
    ]
  }
}

My work so far: Try 1:

  let selectedCount;
export default resolvers = {
    Query: {
        posts(_, args){
            return Post.findAndCountAll({where: args}).then(
                function (results) {
                    selectedCount = results.count;
                    return results.rows
                });
        },
        numberOfPosts(){
            return selectedCount
        }
    }}

So I am defining a helping variable outside of resolvers, and set it to the number of selected rows, then the count is returned in numberOfPosts(), which works, but the problem with this is, return results.rows causes an error, and I do not understand why.

another issue is, that selectedCount is always the previous number of rows

Try 2

Another solution that seems to work is to Pass the arguments twice into the GraphQL query, like so:

{
  numberOfPosts(filter: "example") {
    total
    filtered
  }
  posts(filter: "example") {
    id
    date
    text
  }
}

Then both resolver functions know the same arguments, so I can select and count the same posts. But this looks not right to me, since I have to pass the same args twice, they will also be transmitted twice...

I am using react-apollo on meteor with mysql and sequelize, I am still a beginner in JS. Lets assume I have the following resolver function on my apollo-server:

 export default resolvers = {
     Query: {
         posts(_, args){
             return Post.findAndCountAll({ where: args   });
         },
         numberOfPosts(){
             return /// the number of selected posts
         }
     }

I would like to select some data from the database where some conditions are met and then count the amount of selected rows and return them in the field "numberOfPosts". findAndCountAll() returns an object, which contains the selected rows and the count. I would like to get my post() to return only the selected rows, and my numberOfPosts() to return only the count of the selected posts. Right now, both is returned by posts().

My schema is:

 type Post {
  id: Int
  date: Float
  text: String
}

 type NumberOfPosts{
  total: Int
  filtered: Int
}

type Query {
  posts(
   id: Ind,
   offset: Int,
   limit: Int,
   filter: String): [Post]
  numberOfPosts:[NumberOfPosts] 
}

schema {
  query: Query
}

The Goal is to receive data in the following format:

{
  "data": {
    "numberOfPosts": [
      {
        "total": 1000,
        "filtered": 21
      }
    ],
    "posts": [
      {
        "id": 4,
        "date": 5105626122,
        "text": "jzybiwutudi"
      },
      ...
    ]
  }
}

My work so far: Try 1:

  let selectedCount;
export default resolvers = {
    Query: {
        posts(_, args){
            return Post.findAndCountAll({where: args}).then(
                function (results) {
                    selectedCount = results.count;
                    return results.rows
                });
        },
        numberOfPosts(){
            return selectedCount
        }
    }}

So I am defining a helping variable outside of resolvers, and set it to the number of selected rows, then the count is returned in numberOfPosts(), which works, but the problem with this is, return results.rows causes an error, and I do not understand why.

another issue is, that selectedCount is always the previous number of rows

Try 2

Another solution that seems to work is to Pass the arguments twice into the GraphQL query, like so:

{
  numberOfPosts(filter: "example") {
    total
    filtered
  }
  posts(filter: "example") {
    id
    date
    text
  }
}

Then both resolver functions know the same arguments, so I can select and count the same posts. But this looks not right to me, since I have to pass the same args twice, they will also be transmitted twice...

Share Improve this question edited Jan 3, 2017 at 12:41 henk asked Jan 2, 2017 at 22:57 henkhenk 2,8583 gold badges23 silver badges54 bronze badges 5
  • 1 i don't know anything about react-apollo, but I would highly remend NOT creating a selectedCount variable where one query would assign the result for another query – hellatan Commented Jan 3, 2017 at 3:11
  • thank you, do you have any tips how to pass the result to the other query? – henk Commented Jan 3, 2017 at 3:33
  • i'm taking it that these are two independent queries and not two related fields on one query? – hellatan Commented Jan 3, 2017 at 7:53
  • it seems like these resolver methods correspond directly with your schema. can you update your question and post an example of what that looks like? If your rootValue has a field name numberOfPosts being returned already, then you don't need to add this resolver. Would it make more sense to design the db to always have a field that contains that value instead? – hellatan Commented Jan 3, 2017 at 8:27
  • Maybe, but I don't know how to do that yet. I have edited my Question, please take a look at it again. – henk Commented Jan 3, 2017 at 12:35
Add a ment  | 

1 Answer 1

Reset to default 6

You should think more about the design and what each of those queries should do. Those queries should not mutate the database or the global state.

The best thing you can do is to simply define a new type that includes total and filtered, like what you did as NumberOfPosts in your first try, and also the list of posts.

So, your schema would be like:

type Post {
  id: Int
  date: Float
  text: String
}

type PostList {
  total: Int
  filtered: Int
  posts: [Post]
}

type Query {
  posts(
    id: Ind,
    offset: Int,
    limit: Int,
    filter: String): PostList
}

schema {
  query: Query
}

And you resolve posts like:

posts(_, args) {
  return Post.findAndCountAll({ where: args }).then(result => {
    return {
      total: 1000,
      filtered: result.count,
      posts: result.rows
    }
  })
}

Notice how I just put 1000 for the total number. You can not get the total number of rows with findAndCountAll. If you that, need you can run two different queries in parallel and use Promise.all to wait for them to be resolved.

posts(_, args) {
  return Promise.all([
    Post.count(),
    Post.findAndCountAll({ where: args })
  ]).then(data => {
    return {
      total: data[0],
      filtered: data[1].count,
      posts: data[1].rows
    }
  })
}

The above code also could benefit from ES6's destructuring:

posts(_, args) {
  return Promise.all([
    Post.count(),
    Post.findAndCountAll({ where: args })
  ]).then(([totalCount, filteredData]) => {
    return {
      total: totalCount,
      filtered: filteredData.count,
      posts: filteredData.rows
    }
  })
}

Now you can run:

query {
  posts(filter:"example") {
    total
    filtered
    posts {
      id
      date
      text
    }
  }
}

and get:

{
  "data": {
    "posts": {
      "total": 1000,
      "filtered": 21,
      "posts": [
        {
          "id": 4,
          "date": 5105626122,
          "text": "jzybiwutudi"
        },
        ...
      ]
    }
  }
}
发布评论

评论列表(0)

  1. 暂无评论