Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

graphql with sequelize join foreign key

I made simple board api system with graphql.

And I use sequelize(version 4) for connect to database.

[schema.graphql]

type Article {
    article_no: Int!
    subject: String!
    content: String!
    createdAt: String!
    updatedAt: String!
    comment: String
}

type Comment {
    article_no: Int!
    content: String!,
    createdAt: String!
}

type Query {
    articles: [Article]!
    article(article_no: Int!): Article
    comments: [Comment]!
    comment(article_no: Int!): Comment
}

type Mutation {
    createArticle(subject: String!, content: String!, password: String!): Boolean!
    createComment(article_no: Int!, content: String!, password: String!): Boolean!
}

[resolvers.js]

import { Article, Comment } from './db';

const resolvers = {
    Query: {
        articles: async () => {
            return Article.all();
        },
        article: async(_, args) => {
            return Article.find({
                where: args.article_no,
            });
        },
        comments: async () => {
            return Comment.all();
        },
        comment: async(_, args) => {
            return Comment.find({
                where: args.article_no
            });
        }
    },
    Mutation: {
        createArticle: async (_, args) => {
            try {
                const article = await Article.create({
                    subject: args.subject,
                    content: args.content,
                    password: args.password
                });
                return true;
            } catch(e) {
                return false;
            }
        },
        createComment: async(_, args) => {
            try {
                const comment = await Comment.create({
                    article_no: args.article_no,
                    content: args.content,
                    password: args.password
                })
                return comment;
            } catch(e) {
                return false;
            }
        }
    }
}

export default resolvers;

[db.js]

const Sequelize = require('sequelize');
import config from '../config/config';

const db = new Sequelize(config.DB, config.USER, config.PASS, {
    host: 'localhost',
    dialect: 'mysql'
})

export const Article = db.define('article', {
    article_no: {
        type: Sequelize.INTEGER,
        primaryKey: true,
        autoIncrement: true
    },
    subject: {
        type: Sequelize.STRING(30),
        allowNull: false
    },
    content: {
        type: Sequelize.STRING(100),
        allowNull: false
    },
    password: {
        type: Sequelize.STRING(20),
        allowNull: false
    },
    comment: Sequelize.STRING
}, {
    freezeTableName: true,
    timestamps: true,
    underscored: true
})

export const Comment = db.define('comment', {
    content: {
        type: Sequelize.STRING(150),
        allowNull: false
    },
    password: {
        type: Sequelize.STRING(20),
        allowNull: false
    },
}, {
    freezeTableName: true,
    timestamps: true,
    underscored: true
})

Article.hasMany(Comment, {
    foreignKey: 'article_no',
    scope: {
        comment: 'comment'
    }
})
Comment.belongsTo(Article, {
    foreignKey: 'article_no',
    targetKey: 'article_no',
    allowNull: false,
    as: 'comment'
});
db.sync()
.then(console.log('[*] DB Sync Done'))

Article and Comment is 1:N realtionship.

So I set hasMany to Article and set belongsTo to Comment.

Also Comment as comment and include it to Article's scope.

But when I request query { article(id:1) { subject, comment } },

comment return null.

I refer document http://docs.sequelizejs.com/manual/tutorial/associations.html#foreign-keys and follow as well.

But it doesn't work.

My Expected result is here:

{
  "data": {
    "article": {
      "subject": "test",
      "comment": {
           "article_no":1,
           "content: "first comment",
           "created_at": "2018010101001",
           # every comment related article is here
      }
    }
  }
}

Current result is here:

{
  "data": {
    "article": {
      "subject": "test",
      "comment": null
    }
  }
}

I want to display all the comments that related specific article.

Is there any solution about this?

Thanks.

like image 282
Hide Avatar asked Jul 04 '18 02:07

Hide


2 Answers

Couple of notes to get you on the right track:

When defining a relationship, keep in mind that the model whose method you are calling is the one that you are effectively adding a property to. For example, if you call Article.hasMany(Comment), this will create a comments property on the Article model and will affect the Comment model. Likewise, calling Comment.belongsTo(Article) will create an article property on the Comment model and not affect the Article model.

Note that even if the relationship is created, if you want to include the associated comments when you query an article (or vice versa), you must pass in the appropriate include option. This can be done directly in the query call, i.e.

Article.findAll({ include: [Comment] })

or can be part of a scope, like the default scope. Scopes can be set as part of the model's definition, or added after the fact by calling addScope. For example, you could do:

Article.addScope('defaultScope', {
  include: [Comment],
}, { override: true })

Note: The override here is necessary because the default scope already exists. To query the associated models, your query call or the scope you're using must include the appropriate include array. Associations also have the idea of "scope" but it's different from a model's scope. See the docs here for a discussion of the differences.

Lastly, when passing a where option to your find call, you should make sure it includes the property names you want to query against, i.e.

Article.find({ where: { article_no: args.article_no } })

// or possibly even
Article.find({ where: args })
like image 66
Daniel Rearden Avatar answered Oct 17 '22 21:10

Daniel Rearden


There are problems with your graphql schema, and your sequelize schema...

Lets look at your graphql schema

type Article {
    ...
    comment: String
}

You wrote that Article and Comment have a 1:M relation but here the comment field is of type string and not even an array of string

the correct type definition for Article should be (imo):

type Article {
    ...
    comments: [Comment] 
}

now if you make the adjustments to your sequelize schema that @Daniel-Rearden wrote in his answer your Article model should have a comments property so it will be returned by default from the default resolver of the Article type

like image 35
Daniel Jakobsen Hallel Avatar answered Oct 17 '22 21:10

Daniel Jakobsen Hallel