首页 > 解决方案 > Apollo graphql 正在为 mongodb 中的空子文档返回空数据

问题描述

我在我的 apollo graphql 突变中添加了另一个字段(联系人),但是在检索该字段时它会产生错误数据。即使匹配的 mongodb 字段是否有真实数据,graphql 也会返回具有空值的多个字段。

我已经尝试在 apollo 客户端 graphql 选项中删除 __typename ,但它没有帮助。当前堆栈是:

reactjs 16.8.5
react-apollo 2.5.2
mongodb 3.6.11
mongoose 5.3.6
apollo-server 2.3.1 

我不明白为什么这样做,因为我有另一个几乎相同但返回正确的子文档。

// CLIENTSIDE
// APOLLO SETUP
const cache = new InMemoryCache({
   dataIdFromObject: object => object.key || null
 })

 const AuthLink = (operation, forward) => {
   const token = cookies._uid
   operation.setContext(context => ({
     ...context,
     headers: {
       ...context.headers,
       authorization: token
     }
   }))

   return forward(operation)
 }

 const httpLink = new HttpLink({
   uri:"/graphql",
   credentials: "include"
 })

// mutation
 export const LOGIN_MUTATION = gql`
  mutation loginMutation($email: String!, $password: String!) {
    login(input: {email: $email, password: $password}) {
      token
      user {
        _id
        contacts {  // This is the subfield in question
          _id
          username
        }
        subscriptions {  // This subfield returns corretly
          _id
          title
          levels {
            _id
          }
        }
      }
      error {
        path
        message
      }
    }
  }
`

// SERVERSIDE
// APOLLO SETUP
 const baseSchema = `
   schema {
     query: Query,
     mutation: Mutation
   }
 `
 const schema = makeExecutableSchema({
   typeDefs: [
     userTypeDefs,
   ],
   resolvers: merge(
     {},
     userResolvers,
   )
 })

 const {ObjectId} = mongoose.Types
 ObjectId.prototype.valueOf = function() {
  return this.toString()
 }

 export default new ApolloServer({
   introspection: true,
   credentials: true,
   schema,
   context: ({req, res}) => ({
     url: req.protocol + "://" + req.get("host"), 
     req
   })
 })

// USER MONGOOSE MODEL
 export const UserSchema = new mongoose.Schema(
   {
     contacts: [
       {
         type: mongoose.Schema.Types.ObjectId,
         ref: "User"
       }
     ],     
     firstName: {
       type: String
     },     
     lastName: {
       type: String
     },     
     username: {
       type: String,
       lowercase: true,
       unique: true,
       required: [true, "can't be blank"],
       match: [/^[a-zA-Z0-9]+$/, "is invalid"],
       index: true
     },

     sentRequests: [
       {
         username: {
           type: String,
           default: ""
         }
       }
     ],     
     subscriptions: [
       {
         type: mongoose.Schema.Types.ObjectId,
         ref: "Course"
       }
     ],
     password: {
       default: "",
       required: [true, "can't be blank"],
       type: String
     }
   },
   {timestamps: true}
 )

 UserSchema.plugin(uniqueValidator, {message: "is already taken."})
 export default mongoose.model("User", UserSchema)

// USER GRAPHQL SCHEMA
type User {
   _id: ID
   contacts: [User]
   email: String!
   username: String
   subscriptions: [Course]
   createdAt: String
   updatedAt: String
 }

 type AuthPayload {
   token: String
   user: User
   error: [Error]
 }

 input LoginInput {
   email: String!
   password: String!
 }

 type Mutation {
   login(input: LoginInput): AuthPayload
 }

// USER RESOLVER
 const login = async (parent, args, ctx, info) => {   
   let email = args.email

   let user = await User.findOne({email})
     .populate("subscriptions")
     .populate("contacts")
     .exec()

  if (!user) {
     arrayOfErrors.push({
       path: "email",
       message: "invalid email"
     })
   } else if (user) {

   console.log("user: ", user)


   return {
     user,
     error: arrayOfErrors
   }
 }

 Mutation: {
   login
 }
// CONSOLE LOG CLIENTSIDE
user:
  confirmed: true
  contacts: Array(3)  // returns an array of 3 items??  It's [] in mongodb
    0: {_id: null, username: null}
    1: {_id: null, username: null}
    2: {_id: null, username: null}
    length: 3
    __proto__: Array(0)
  subscriptions: Array(1)
    0: {_id: "5cd36fc1c8d1e222b99d9c58", title: "Korean Class 101 Study", 
    length: 1
    __proto__: Object
__proto__: Object

// CONSOLE LOG SERVERSIDE
POST /graphql 200 64.359 ms - -
user: {
  contacts: [ ],
  subscriptions:
   [ { _id: 5cd6f7f8212af32c75555d4b,
       subscribers: 2,
       owner: 5cd36edec8d1e222b99d9c57,
       createdAt: 2019-05-09T00:09:37.845Z,
       updatedAt: 2019-05-11T16:36:14.661Z,
       __v: 23 } ],
  password: '$2b$10$bkjiazklcoqlkJSJSAioxoAqkoajsdjnqjkiaallaadfadfp7zS',
  _id: 5cd36edec8d1e222b99d9c57,
  email: 'example@test.com',
  username: 'example',
  createdAt: 2019-05-09T00:05:50.314Z,
  updatedAt: 2019-05-29T17:23:21.545Z,
  __v: 32
}

我希望一个空数组返回 [ ],而不是 graphql 返回一个包含 3 个具有空值的项目的数组。即使我将真实联系人添加到数据库中,它仍会返回 3 个具有空值的项目。订阅正确返回,但它几乎与联系人字段相同,只是在猫鼬模型中是“课程”类型而不是“用户”类型。

标签: reactjsmongodbmongooseapolloapollo-client

解决方案


我怀疑任何人都会遇到这种类型的错误,但如果你这样做,这里有一个解决方案。在开发过程中,我将此代码放在解析器中以进行测试。删除它解决了这个问题。

// USER RESOLVER
...
Query: {...},

/* code to remove
User: {
  contacts: user => {
    return ["Mo", "Larry", "Curly"]
  }
}
*/ 

Mutation: {...}

一件非常微不足道的事情,但几个月没有出现在这个实际代码中,所以很难发现。我从没想过这三个傀儡会让我如此头疼。


推荐阅读