Это тесно связано с моим последним вопросом здесь .Короче говоря, у меня есть 2 схемы: dbPosts и dbAuthors .Они выглядят примерно так (для краткости я опустил некоторые поля здесь):
dbPosts
id: mongoose.Schema.Types.ObjectId,
title: { type: String },
content: { type: String },
excerpt: { type: String },
slug: { type: String },
author: {
id: { type: String },
fname: { type: String },
lname: { type: String },
}
dbAuthors
id: mongoose.Schema.Types.ObjectId,
fname: { type: String },
lname: { type: String },
posts: [
id: { type: String },
title: { type: String }
]
Я разрешаю свой пост запросов вот так:
const mongoose = require('mongoose');
const graphqlFields = require('graphql-fields');
const fawn = require('fawn');
const dbPost = require('../../../models/dbPost');
const dbUser = require('../../../models/dbUser');
fawn.init(mongoose);
module.exports = {
// Queries
Query: {
posts: (root, args, context) => {
return dbPost.find({});
},
post: (root, args, context) => {
return dbPost.findById(args.id);
},
},
Post: {
author: (parent, args, context, ast) => {
// Retrieve fields being queried
const queriedFields = Object.keys(graphqlFields(ast));
console.log('-------------------------------------------------------------');
console.log('from Post:author resolver');
console.log('queriedFields', queriedFields);
// Retrieve fields returned by parent, if any
const fieldsInParent = Object.keys(parent.author);
console.log('fieldsInParent', fieldsInParent);
// Check if queried fields already exist in parent
const available = queriedFields.every((field) => fieldsInParent.includes(field));
console.log('available', available);
if(parent.author && available) {
return parent.author;
} else {
return dbUser.findOne({'posts.id': parent.id});
}
},
},
};
И я разрешаю все автор запросов вот так:
const mongoose = require('mongoose');
const graphqlFields = require('graphql-fields');
const dbUser = require('../../../models/dbUser');
const dbPost = require('../../../models/dbPost');
module.exports = {
// Queries
Query: {
authors: (parent, root, args, context) => {
return dbUser.find({});
},
author: (root, args, context) => {
return dbUser.findById(args.id);
},
},
Author: {
posts: (parent, args, context, ast) => {
// Retrieve fields being queried
const queriedFields = Object.keys(graphqlFields(ast));
console.log('-------------------------------------------------------------');
console.log('from Author:posts resolver');
console.log('queriedFields', queriedFields);
// Retrieve fields returned by parent, if any
const fieldsInParent = Object.keys(parent.posts[0]._doc);
console.log('fieldsInParent', fieldsInParent);
// Check if queried fields already exist in parent
const available = queriedFields.every((field) => fieldsInParent.includes(field));
console.log('available', available);
if(parent.posts && available) {
// If parent data is available and includes queried fields, no need to query db
return parent.posts;
} else {
// Otherwise, query db and retrieve data
return dbPost.find({'author.id': parent.id, 'published': true});
}
},
},
};
Опять-таки, я в целях краткости оставил не относящиеся к этому вопросу биты, такие как мутации.Моя цель - сделать все запросы рекурсивными, а также оптимизировать поиск в базе данных.Но почему-то я не могу этого сделать.Вот один запрос, который я выполняю, например:
{
posts{
id
title
author{
first_name
last_name
id
posts{
id
title
}
}
}
}
И он возвращает это:
{
"errors": [
{
"message": "Cannot return null for non-nullable field Post.author.",
"locations": [
{
"line": 5,
"column": 5
}
],
"path": [
"posts",
1,
"author"
]
}
],
"data": {
"posts": [
{
"id": "5ba1f3e7cc546723422e62a4",
"title": "A Title!",
"author": {
"first_name": "Bill",
"last_name": "Erby",
"id": "5ba130271c9d440000ac8fc4",
"posts": [
{
"id": "5ba1f3e7cc546723422e62a4",
"title": "A Title!"
}
]
}
},
null
]
}
}
Если вы заметили, этот запрос возвращает все запрошенные значения, но также добавляетсообщение об ошибке на запрос post.author !Что может быть причиной этого?
Я не включил всю кодовую базу, чтобы не сбивать с толку, но если вы хотите взглянуть, он работает на Github и GraphiQLинтерфейс на https://graph.schandillia.com, если вы хотите увидеть результаты для себя.
Большое спасибо за ваше время, если вы зашли так далеко.Буду очень признателен за любой указатель в правильном направлении! "
PS : Если вы заметили, я записываю значения 3 переменных в каждом преобразователе для целей отладки:
- queriedFields : массив всех запрашиваемых полей
- fieldsInParent : массив всех полей, возвращаемых в parent резолверасвойство
- доступно : логическое значение, показывающее, существуют ли все queriedFields члены в fieldsInParent
И когда я запускаюпростой запрос, подобный следующему:
{
posts{
id
author{
id
posts{
id
}
}
}
}
Вот что регистрируется:
-------------------------------------------------------------
from Post:author resolver
queriedFields [ 'id', 'posts' ]
fieldsInParent [ '$init', 'id', 'first_name', 'last_name' ]
available false
-------------------------------------------------------------
from Post:author resolver
queriedFields [ 'id', 'posts' ]
fieldsInParent [ '$init', 'id', 'first_name', 'last_name' ]
available false
-------------------------------------------------------------
from Author:posts resolver
queriedFields [ 'id' ]
fieldsInParent [ 'id', 'title' ]
available true
Разве post: author resolver не может выполняться только один раз?Забавно, что в первых двух журналах fieldsInParent отсутствует поле posts , даже если схема для author включает такое поле.