非规范化架构?

Denormalized schema?

猫鼬模式:

const postSchema = new mongoose.Schema({
    title: { type: String },
    content: { type: String },

    comments: {
        count: { type: Number },
        data: [{
            author: {
                type: mongoose.Schema.Types.ObjectId,
                ref: 'User'
            },
            content: { type: String },
            created: { type: Date },

            replies: [{
                author: {
                    type: mongoose.Schema.Types.ObjectId,
                    ref: 'User'
                },
                content: { type: String },
                created: { type: Date },
            }]
        }]
    }
})

我不想规范化评论和回复,因为:


如果我将它归一化,我将不得不:


这是 MongoDB 的最大优势之一:专门对数据进行分组以满足您的应用程序数据需求,但 GraphQL 和 Relay.js 似乎不支持?

问题:

有没有办法让评论嵌套在单个 post 对象中(或者至少让回复嵌套在单个评论中)以便在一次读取中获得全部内容?


GraphQL 架构:

const postType = new GraphQLObjectType({
    name: 'Post',
    fields: () => ({
        id: globalIdField('Post'),
        title: { type: GraphQLString },
        content: { type: GraphQLString },

        comments: {

            // ?????

        }
    }),
    interfaces: [nodeInterface],
})

更新:

const postType = new GraphQLObjectType({
    name: 'Post',
    fields: () => ({
        id: globalIdField('Post'),
        title: { type: GraphQLString },
        content: { type: GraphQLString },

        commentCount: { type: GraphQLInt },
        comments: { type: new GraphQLList(commentType) }
    }),
    interfaces: [nodeInterface]
})

const commentType = new GraphQLObjectType({
    name: 'Comment',
    fields: () => ({
        content: { type: GraphQLString },
        created: { type: GraphQLString },
        author: {
            type: userType,
            resolve: async (comment) => {
                return await getUserById(comment.author)
            }
        },
        replies: {
            type: new GraphQLList(commentType),
            resolve: (comment) => {

                // Log is below
                console.log(comment)

                // Error only occurs if I return it!
                return comment.replies
            }
        }
    })
})

日志 (comment):

{ 
  author: 'user-1',
  created: '05:35'
  content: 'Wow, this is an awesome comment!',
  replies:
     [{ 
       author: 'user-2',
       created: '11:01',
       content: 'Not really..',
     },
     {  
       author: 'user-1',
       created: '11:03',
       content: 'Why are you so salty?',
     }]
}

This is one of the biggest strengths of MongoDB: to group your data specifically to suit your application data needs but GraphQL and Relay.js doesn't seem to support that?

GraphQL 确实支持您尝试做的事情。在进入细节之前,我们需要记住 GraphQL 是关于公开数据,而不是关于我们如何存储数据。我们可以以任何我们喜欢的方式存储——规范化或非规范化。我们只需要告诉 GraphQL 如何获取我们在 GraphQL 模式中定义的数据。

Is there a way to get comments nested inside of a single post object (or at least get replies nested inside of a single comment) in order to get the whole thing in a single read?

是的,这是可能的。您只需将评论定义为列表。但是,GraphQL 不支持 GraphQL 对象类型中的任意类型的字段。因此,我们需要定义单独的 GraphQL 类型。在您的猫鼬模式中,comments 是一个具有 count 条评论和 data 条评论的对象。 data 属性 是另一类对象的列表。因此,我们需要定义两个 GraphQL 对象 - CommentCommentList。代码如下所示:

const commentType = new GraphQLObjectType({
  name: 'Comment',
  fields: () => ({
    author: { type: GraphQLString },
    content: { type: GraphQLString },
    created: { type: GraphQLString },
    replies: { type: new GraphQLList(commentType) },
  }),
});

const commentListType = new GraphQLObjectType({
  name: 'CommentList',
  fields: () => ({
    count: {
      type: GraphQLInt,
      resolve: (comments) => comments.length,
    },
    data: {
      type: new GraphQLList(commentType),
      resolve: (comments) => comments,
    },
  }),
});

const postType = new GraphQLObjectType({
  name: 'Post',
  fields: () => ({
    id: globalIdField('Post'),
    title: { type: GraphQLString },
    content: { type: GraphQLString },

    comments: {
      type: commentListType,
      resolve: (post) => post.comments,
    }
  }),
  interfaces: [nodeInterface],
});

I don't want to normalize comments and replies because:

  • I will always need post comments together (read in a single go)
  • I will never use comments to query or sort anything
  • It's so much easier to create, update and delete post with comments (document locking)

以上述方式定义 post 和注释 GraphQL 对象类型让您:

  • 一起阅读所有 post 条评论
  • 不要使用注释查询,因为它甚至没有id字段。
  • 使用您喜欢的数据库以您喜欢的任何方式实施评论操作。 GraphQL 与它无关。