Git Product home page Git Product logo

lookahead's Introduction

Lookahead

Look Ahead GraphQL fields with recursive joins ($lookup) using Mongo aggregation pipelines for Apollo queries, thus eliminating N+1 problem in GraphQL completely.

Future

I am building Version 2 of this library which would allow you to recursively convert Nested GraphQL request into N Level Nested Lookups Queries, Along with support for different stages such as Match, Limit & Sort. You may wanna look into mongo-aggregation-builder, an easier and readable way of building mongodb aggregation pipelines.

Overview

A Apollo/MongoDB based project uses GraphQL resolvers to recursively fetch fields from Mongo collections. This approach is often sufficient in most of the cases, however it suffers from a major issue.

  • GraphQL attempts to fetch fields recursively due to which single request can lead to many database requests. It's easy to see how we can quickly reach hundreds of lookups for a single Apollo query. This issue can be solved by performing a single Mongo aggregation that fetches all the data in one go, performing lookups on the related collections, so that we can then sort or filter on any field in the result.

lookahead does all the heavy lifting for you:

  1. It analyses the resolveInfo data passed to the top-level resolver in order to extract the hierarchy of fields that have been requested. It does this to ensure that it only performs the joins required for the actual query.

  2. From this information it builds a single Mongo aggregation pipeline that recursively performs lookups for the other collections used in the request.

    You can then include the pipeline as part of a larger aggregation pipeline that sorts and filters the result.

Installation

npm install lookahead

You'll also need to include lookahead's type definition and directive when calling Apollo's makeExecutableSchema:

import { mergeTypes } from 'merge-graphql-schemas';
import { lookAheadDirective } from 'lookahead';

...


const { lookAheadDirectiveTypeDefs, lookAheadDirectiveTransformer } = lookAheadDirective('lookahead');

let schema = makeExecutableSchema({
  typeDefs: mergeTypes([lookAheadDirectiveTypeDefs, ...yourTypes]),
  resolvers,
});

schema = lookAheadDirectiveTransformer(schema)

Specifying the Joins

lookahead needs to know which fields are joins, and how to join them. In order to make this both easy to specify and declarative, a custom GraphQL directive, @lookahead, is used to specify this information directly in the types declaration. Here's an example:

type Company {
  ...
  user: User @lookahead(lookup: { collection: "users", localField: "userId", foreignField: "_id" })
}

type Query {
  ...
  companies: [Company!]!
}

Writing the Resolvers

In your resolvers you'll call createPipeline to create the aggregation pipeline:

import { createPipeline } from 'lookahead';

...

const companies = (_, { limit = 20 }, context, resolveInfo) => {
  // Create a pipeline to first perform any initial matching, then do the lookups and finally fetch the results
  const pipeline = [
    // Perform any initial matching that you need.
    // This would typically depend on the parameters passed to the query.
    { $match: { type: 'b2b' } }

    // Include all the pipeline stages generated by lookahead to do the lookups
    // We pass `null` since the `users` query is mapped directly to the result
    // of an aggregation on the Users collection.
    ...createPipeline(null, resolveInfo, context),

    // Filter, sort or limit the result.
    { $limit: limit },
  ];

  // How you call Mongo will depend on your code base. You'll need to pass your pipeline to Mongo's aggregate.
  // This is how you'd do it using `mongoose`
  return CompanyCollection.aggregate(pipeline);
});

lookahead's People

Contributors

smithg09 avatar

Watchers

 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.