Mongoose .populate() not working correctly

Viewed 1294

I'm trying to create a Tumblr clone with GraphQL and MERN. Right now I'm just trying to create the template for posts with photos.

Just in case it's relevant, I am doing regular REST post requests with axios and express for the image files. I take the response from those, map over the _ids and send them in the createPost mutation.

In graphiql I can query for a single Image model and get everything back fine, like so:

{
  image(_id: "someId"){
    _id
    url
   created
  }
}

But when I do a subquery with the ObjectIds I've pushed into the Post arrays I get null for everything besides _id and __typename:

{
  post(_id: "someId"){
    _id
    mainImages {
     _id   //returns value
     url  //returns null
     created   //returns null
     __typename   //returns value
   }
  }
}

The posts have two arrays of objects with ObjectId and ref for images, the Post model:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const PostSchema = new Schema({
  mainImages: [
    {
      type: Schema.Types.ObjectId,
      ref: 'Image'
    }
  ],
  bodyImages: [
    {
      type: Schema.Types.ObjectId,
      ref: 'Image'
    }
  ],
})

module.exports = mongoose.model('Post', PostSchema, 'posts')

The Image model:

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const ImageSchema = new Schema({
  url: {
    type: String,
    required: true
  },
  created: {
    type: Date,
    required: true
  }
})

module.exports = Image = mongoose.model('Image', ImageSchema, 'images');

The PostType:

const PostType = new GraphQLObjectType({
  name: 'PostType',
  fields: () => ({
    _id: { type: GraphQLID },
    mainImages: { 
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('images')
          .then(post => post.mainImages)
      }
    },
    bodyImages: {
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('images')
          .then(post => post.bodyImages)
      }
    },
  })
})

module.exports = PostType;

I'm wondering if .populate('images') isn't working correctly. I thought that if you have the ObjectIds then .populate() can take care of the rest. I've been looking around at a bunch of different questions but none of them have seemed to be relevant enough to my situation, and the GraphQL and Mongoose docs also haven't given me a breakthrough yet.

1 Answers

Alright so in the latest edition of I wasn't reading the docs correctly, I finally figured out what I was doing wrong.

.populate() takes a string that denotes a path to the field within the document that you're trying to populate the field of.

I figured out the solution while I was reading about populating multiple fields in a single document.

For some reason I thought the 'path' was supposed to point to the name of the collection in the database:

const PostType = new GraphQLObjectType({
  name: 'PostType',
  fields: () => ({
    _id: { type: GraphQLID },
    mainImages: { 
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('images') //incorrectly pointing towards the collection in db
          .then(post => post.mainImages)
      }
    },
    bodyImages: {
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('images') //incorrectly pointing towards the collection in db
          .then(post => post.bodyImages)
      }
    },
  })
})

module.exports = PostType;

It's supposed to point back in to the document/model itself:

const PostType = new GraphQLObjectType({
  name: 'PostType',
  fields: () => ({
    _id: { type: GraphQLID },
    mainImages: {      //this is the 'path'
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('mainImages') //that's referenced here
          .then(post => post.mainImages)
      }
    },
    bodyImages: { 
      type: new GraphQLList(ImageType),
      resolve(parentValue) {
        return Post.findById(parentValue._id)
          .populate('bodyImages') //and once again
          .then(post => post.bodyImages)
      }
    }
  })
})

export default PostType;

And that solved my problem, all of my GraphQL subqueries are working correctly now. Another day, another episode of I didn't read the docs correctly.

Related