非规范化模式?
Posted
技术标签:
【中文标题】非规范化模式?【英文标题】:Denormalized schema? 【发布时间】:2016-12-14 03:28:57 【问题描述】:Mongoose 架构:
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 ,
]
]
)
我不想标准化 cmets 和回复,因为:
我总是需要一起发布 cmets(一口气读完) 我永远不会使用 cmets 来查询或排序任何东西 使用 cmets 创建、更新和删除帖子要容易得多(文档锁定)如果我将其标准化,我将不得不:
从数据库中获取帖子 从数据库中获取 cmets 获取每条评论的回复这是 MongoDB 的最大优势之一:专门对数据进行分组以满足您的应用程序数据需求,但 GraphQL 和 Relay.js 似乎不支持这一点?
问题:
有没有办法让 cmets 嵌套在单个帖子对象中(或者至少让回复嵌套在单个评论中),以便一次读取整个内容?
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?',
]
【问题讨论】:
制作“cmets”对象数组,以便您可以使用一个查询轻松访问它。 【参考方案1】:这是 MongoDB 的最大优势之一:专门对数据进行分组以满足您的应用程序数据需求,但 GraphQL 和 Relay.js 似乎不支持这一点?
GraphQL 确实支持您正在尝试做的事情。在进入细节之前,我们需要记住 GraphQL 是关于公开数据,而不是关于我们如何存储数据。我们可以以任何我们喜欢的方式存储 - 标准化与否。我们只需要告诉 GraphQL 如何获取我们在 GraphQL 模式中定义的数据。
有没有办法让 cmets 嵌套在单个帖子对象中(或者至少让回复嵌套在单个评论中),以便一次读取整个内容?
是的,这是可能的。您只需将 cmets 定义为列表。但是,GraphQL 不支持 GraphQL 对象类型中的任意类型的字段。因此,我们需要定义单独的 GraphQL 类型。在您的猫鼬模式中,comments
是一个具有 count
的 cmets 和 cmets data
的对象。 data
属性是另一种对象的列表。所以,我们需要定义两个 GraphQL 对象——Comment
和CommentList
。代码如下:
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],
);
我不想标准化 cmets 和回复,因为:
我总是需要一起发布 cmets(一口气读完) 我永远不会使用 cmets 来查询或排序任何东西 使用 cmets 创建、更新和删除帖子要容易得多(文档锁定)
以上述方式定义 post 和 comment GraphQL 对象类型让您:
一起阅读所有post cmets 不要使用评论查询,因为它甚至没有id
字段。
使用您喜欢的数据库以您喜欢的任何方式实现 cmets 操作。 GraphQL 与它无关。
【讨论】:
知道为什么我会收到错误User Error: expected iterable, but did not find one for field Comment.replies.
?
您是否查看了null
的回复?一条评论可能没有任何回复。在这种情况下,根据您的实现,replies
可以是 null
或空数组。在没有回复的情况下空数组更好恕我直言,因为它避免了检查null
的需要。
回复要么是填充的要么是空数组。。仍然不确定是什么问题..
comment.replies
的解析功能如何?
仅type: new GraphQLList(commentType)
,因为名称匹配。我也试过resolve: (comment) => comment.replies
,但还是同样的错误。以上是关于非规范化模式?的主要内容,如果未能解决你的问题,请参考以下文章