This library create field projection from GraphQL query
There are many libraries can do the same function. However, starting in MongoDB 4.4, the Path Collision Restrictions are introduced . And it is illegal to project an embedded document with any of the embedded document's fields:
db.inventory.find({}, { size: 1, "size.uom": 1 }); // Invalid starting in 4.4
- And this library is created to remove the collision.
- This library can work with dataloader also
npm install graphql-fields-mongo
Please see the following examples
Given the following query
query user {
user(id: 123) {
id
address
info {
firstName
lastName
}
}
}
const { createSelectedFields } = require('graphql-fields-mongo');
resolve(parent, args, context, info){
const selectedFields = createSelectedFields(info); // [ 'id', 'address', 'info.firstName', 'info.lastName' ]
}
Given the following query
query user {
user(id: 123) {
id
address
info {
firstName
lastName
}
}
}
const { createSelectedFields } = require('graphql-fields-mongo');
resolve(parent, args, context, info){
// Now you like to get more fields for further resolve: `timezone`, and `info` object
const selectedFields = createSelectedFields(info, { additionalFields: ['info', 'address', 'timezone'] }); // [ 'id', 'info', 'timezone' ]
}
Given the following query
query purchase {
purchase(id: 123) {
id
buyer {
id
address
info {
firstName
lastName
}
}
product {
id
# ...others
}
}
}
const { createSelectedFields } = require('graphql-fields-mongo');
resolve(parent, args, context, info){
// Now you like to get selected fields of `buyer`
const selectedFields = createSelectedFields(info, { path: 'buyer' }); // [ 'id', 'address', 'info.firstName', 'info.lastName' ]
// OR with additionalFields
const selectedFields2 = createSelectedFields(info, {
path: 'buyer', additionalFields: ['info', 'address', 'timezone'],
}); // [ 'id', 'info', 'timezone' ]
}
By the default the return result will be an array of projected fields. But you can also get the string or object
query user {
user(id: 123) {
id
address
info {
firstName
lastName
}
}
}
const { createSelectedFields } = require('graphql-fields-mongo');
resolve(parent, args, context, info){
const resultArray1 = createSelectedFields(info); // [ 'id', 'address', 'info.firstName', 'info.lastName' ]
const resultArray2 = createSelectedFields(info, { returnType : 'array' }); // [ 'id', 'address', 'info.firstName', 'info.lastName' ]
const resultString = createSelectedFields(info, { returnType : 'string' } ); // 'id address info.firstName info.lastName'
const resultObject = createSelectedFields(info, { returnType : 'object' }); // { id: 1, address: 1, 'info.firstName': 1, 'info.lastName': 1 }
}
Example 5: Using with Dataloader
query purchase {
purchase(id: 123) {
id
buyer {
id
address
info {
firstName
lastName
}
}
products {
id
sku
name
price
}
}
}
const { createSelectedFields, createMergedSelectedFields } = require('graphql-fields-mongo');
// This is an example with Apollo Federation, but you can run with any resolvers
__resolveReference(parent, context, info) {
const { loaders } = context;
const selectedFields = createSelectedFields(info);
return loaders.product.load(JSON.stringify({ id: parent.id, selectedFields }));
}
// The implementation of `loaders.product()`
async function batchProducts(keys) {
const { ids: productIds, selectedFields } = createMergedSelectedFields(keys);
const products = await Product.find({ _id: { $in: productIds } })
.select(selectedFields)
.lean();
// Don't forget mapping results
// ...
return products;
}
The function createMergedSelectedFields()
supports the following options: