Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deep filtering #75

Open
MegaJSDeveloper opened this issue Jan 9, 2020 · 0 comments
Open

Deep filtering #75

MegaJSDeveloper opened this issue Jan 9, 2020 · 0 comments

Comments

@MegaJSDeveloper
Copy link

MegaJSDeveloper commented Jan 9, 2020

My Schema:

type Post @mongo(name: "posts") {
    _id: ID!
    title: String!
    comments: [Comment] @link(to: "post")
}


type Comment @mongo(name: "comments") {
    _id: ID!
    text: String!
    active: Boolean!
    post: Post @link(field: "postId")
}


type Query {
    posts: [Post]
}

My resolvers:

Post:
  comments: (post)->
    ######################################################################
    # PROBLEM!!!!! 
    return post.comments.filter (comment)=> comment.active

Query:
  posts: (_, args, {db}, ast)=>
    return db.posts.astToQuery(ast).fetch()

This resolver calls AFTER query to database, but how i can filter comments by active prop using by MongoDB engine and reactivity?

I know that I can do this:

Query:
  posts: (_, args, {db}, ast)=>
    return db.posts.astToQuery(ast, {
      embody: ({body})=>
        body.comments.$filters = {active: true}
      return
    }).fetch()

but what if I want to make this filtering a built-in PART OF TYPE Post? instead of writing every time. What if I want, no matter where the Post type appears in the scheme, only active comments are placed in it, without describing the filtering logic every time.

As planned by GraphQL, there are resolvers for this. But then we will face the problem of N + 1. But can we make some kind of virtual resolvers? Which would process virtual data, BEFORE forming a request to the server? And on the basis of these resolvers would the request body be formed? For example, we can pass a virtual cursor to the resolver, to which the programmer can apply some operations and filters. And then, having completed all the virtual resolvers, the engine will make a real request based on these cursors.

And of course, all this should be reactive at any level of depth. Otherwise, what's the point of using a meteor at all.

virtual curcor resolvers:

Post:
  comments: (commentsVirtualCursor)->
    commentsVirtualCursor.filter({
      active: true
      authorId: this.userId
    })
    return commentsVirtualCursor

Query:
  posts: (_, args, {db})=>
    return db.posts.find() # return real cursor

in 99% people just use filters. perhaps we should generally describe a special engine for filters in resolvers. so that having processed all the resolvers, the engine could make a correct and fast and reactive selector. We can also use virtual cursors and virtual collections:

Post:
  comments: (virtualCursor, virtualDB)->

    virtualCurrentUserCursor = virtualDB.users.findOne({
      _id: this.userId
      banned: false
    })

    return virtualCursor.filter({
      author: virtualCurrentUserCursor
    })


Query:
  posts: (_, args, {db})=>
    return db.posts.find() # return real cursor

And we can also use reactive values inside resolvers to re-call the resolver and reactively cause the request to be repeated or only part of the request:

Post:
  comments: (virtualCursor, virtualDB)->
    # reactive value      
    user = getCurrentUser()

    return virtualCursor.filter({
      authorId: user._id
    })
    

Query:
  posts: (_, args, {db})=>
    return db.posts.find() # return real cursor

So that when only one resolver is changed, we do not have to call the entire complex selector, we can make the reactivity granular and dynamically create new sub-selectors only for those parts that change the reactive resolvers, we would select only the changed data with these sub-selectors. And they would substitute into the cache emulating the call of the main complex selector. in addition, when some model is added to the database, we can determine in advance whether it fits our virtual selector or not. Mongo allows this.

Moreover, I propose to describe a special syntax for such filters, like this:

Post:

  comments: (virtualCursor, virtualDB)->
    return virtualCursor.filter("
      authorId == #{this.userId}
      active == true
      text.length > 10
      likeUsers[*].user.age > 18
    ")

all Posts will apply this filter for comments field and be reactive

For example, for each resolver, you can give a virtual cursor pointing to a virtual entity for the place of the entity itself. and a person will be able to virtually filter out some properties of this object.

image

or corny just give access to the query body, If we want to maintain speed, the resolvers must be virtual, and be executed BEFORE querying the database, then they must work with the virtual cursor, or with the query branch tree:

image

Let's rake this damn mess with databases, and let progarmists do creative work, let our magic do the rest =) Any ideas?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant