2
votes

In a brief overview, I'm trying to resolve a list of Users. I have an Apollo Server that stitches an accounts-js schema with my own. So I extended the User type to include some additional fields. Though, in this case I was to be able to return only SOME fields, the rest null.

getUsers: async (_, __, ctx) => {
    let action = await usersModel.find();
    console.log(action)
    return action;  
},

My me query does return all of the data without returning a single null field.

  extend input CreateUserInput {
    isAdmin: Boolean!
  }

  extend type User {
    isAdmin: Boolean
    profile: Profile
    keys: [Key]
  }

  type Profile {
    avatar: String
    bio: String
  }

  type Key {
    id: ID
    livenet: Boolean
    nickname: String
  }
    
  type Query {
    getUsers: [User]
    me: User
  }

Though, when I console.log(action) in the resolver for my query getUsers these are the documents that gets returned in my console.

[ { profile: { bio: 'haha' },
    _id: 5f0a901bdcf725204446c949,
    isAdmin: true,
    services: { password: [Object], email: [Object] },
    createdAt: 1594527771625,
    updatedAt: 1594691054105,
    username: 'ayooo',
    emails: [ [Object] ],
    keys: [ [Object], [Object] ] },
  { profile: { bio: 'testing' },
    _id: 5f0a9439abfce521aba79b2c,
    isAdmin: false,
    services: { password: [Object], email: [Object] },
    createdAt: 1594528825858,
    updatedAt: 1594762680766,
    username: 'lol',
    emails: [ [Object] ],
    keys: [ [Object] ] } ]

Text

If I download my overall GraphQL schema this is what it looks like:

directive @auth on FIELD_DEFINITION | OBJECT
input AuthenticateParamsInput {
  access_token: String
  access_token_secret: String
  provider: String
  password: String
  user: UserInput
  code: String
}

input CreateUserInput {
  isAdmin: Boolean!
  username: String
  email: String
  password: String
}

type CreateUserResult {
  userId: ID
  loginResult: LoginResult
}

type EmailRecord {
  address: String
  verified: Boolean
}

type ImpersonateReturn {
  authorized: Boolean
  tokens: Tokens
  user: User
}

input ImpersonationUserIdentityInput {
  userId: String
  username: String
  email: String
}

type Key {
  id: ID
  livenet: Boolean
  exchange: String
  nickname: String
  apiKey: String
  apiSecret: String
}

type LoginResult {
  sessionId: String
  tokens: Tokens
  user: User
}

type Mutation {
  setBio(bio: String): ID
  setAvatar(avatar: String): ID
  changeUsername(username: String): ID
  setKey(
    livenet: Boolean
    exchange: String
    nickname: String
    apiKey: String
    apiSecret: String
  ): ID
  createUser(user: CreateUserInput!): CreateUserResult
  verifyEmail(token: String!): Boolean
  resetPassword(token: String!, newPassword: String!): LoginResult
  sendVerificationEmail(email: String!): Boolean
  sendResetPasswordEmail(email: String!): Boolean
  addEmail(newEmail: String!): Boolean
  changePassword(oldPassword: String!, newPassword: String!): Boolean
  twoFactorSet(secret: TwoFactorSecretKeyInput!, code: String!): Boolean
  twoFactorUnset(code: String!): Boolean
  impersonate(
    accessToken: String!
    impersonated: ImpersonationUserIdentityInput!
  ): ImpersonateReturn
  refreshTokens(accessToken: String!, refreshToken: String!): LoginResult
  logout: Boolean
  authenticate(
    serviceName: String!
    params: AuthenticateParamsInput!
  ): LoginResult
  verifyAuthentication(
    serviceName: String!
    params: AuthenticateParamsInput!
  ): Boolean
}

type Profile {
  avatar: String
  bio: String
}

type Query {
  getUsers: [User]
  getProfile: Profile
  serverTime: String
  me: User
  twoFactorSecret: TwoFactorSecretKey
  getUser: User
}

type Tokens {
  refreshToken: String
  accessToken: String
}

type TwoFactorSecretKey {
  ascii: String
  base32: String
  hex: String
  qr_code_ascii: String
  qr_code_hex: String
  qr_code_base32: String
  google_auth_qr: String
  otpauth_url: String
}

input TwoFactorSecretKeyInput {
  ascii: String
  base32: String
  hex: String
  qr_code_ascii: String
  qr_code_hex: String
  qr_code_base32: String
  google_auth_qr: String
  otpauth_url: String
}

type User {
  username: String
  isAdmin: Boolean
  profile: Profile
  keys: [Key]
  id: ID!
  emails: [EmailRecord!]
}

input UserInput {
  id: ID
  email: String
  username: String
}

Mind you that a query of getUser or me returns all the data requested. Where as getUsers would only return a little, mostly null for the important stuff that I need to query on my frontend. I'm trying to list users in a table for my admin panel. Maybe this isn't the best approach? Someone let me know!

enter image description here

As opposed to querying me or getUser which returns User. :/

2

2 Answers

1
votes
type Query {
    getUsers: [User]
    me: User
  }

Your query getUsers returns array of User type.

  extend type User {
    isAdmin: Boolean
    profile: Profile
    keys: [Key]
  }

Why extend ? Does any earlier User definition exists? ... anyway graphQL server returns only fields defined in return type. Your User type has only isAdmin, profile and keys properties. Only those fields will be returned.

Solution: Extend your User type definition to get other, existing in DB fields.

1
votes

So after knocking out a lot of other things, I came to realize that It was due to me not fully defining my mongoose schema!


mongoose.connect(process.env.MONGO_URI, {
  useNewUrlParser: true,
  useFindAndModify: false,
  useCreateIndex: true,
  useUnifiedTopology: true,
});

var usersSchema = new mongoose.Schema({
  username: String,
  isAdmin: Boolean,
  emails: [{ 
    verified: Boolean, 
    address: String 
  }],
  profile: {
    avatar: String,
    bio: String,
  },
  keys: [{ 
    nickname: String,
    exchange: String,
    livenet: Boolean,
    apiKey: String,
    apiSecret: String,
  }]
});

export const usersModel = mongoose.model('Users', usersSchema, 'users');