构建我的猫鼬模式的最佳方式:嵌入式数组、填充、子文档?
Posted
技术标签:
【中文标题】构建我的猫鼬模式的最佳方式:嵌入式数组、填充、子文档?【英文标题】:Best way to structure my mongoose schema: embedded array , populate, subdocument? 【发布时间】:2016-09-26 06:01:36 【问题描述】:这是我当前的架构
品牌:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var BrandSchema = new mongoose.Schema(
name: type: String, lowercase: true , unique: true, required: true ,
photo: type: String , trim: true,
email: type: String , lowercase: true,
year: type: Number,
timestamp: type : Date, default: Date.now ,
description: type: String,
location: ,
social:
website: type: String,
facebook: type: String ,
twitter: type: String ,
instagram: type: String
);
风格:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var StyleSchema = new mongoose.Schema(
name: type: String, lowercase: true , required: true,
);
产品
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ProductSchema = new mongoose.Schema(
name: type: String, lowercase: true , required: true,
brandId : type: mongoose.Schema.ObjectId, ref: 'Brand',
styleId: type: mongoose.Schema.ObjectId, ref: 'Style',
year: type: Number ,
avgRating: type: Number
);
帖子:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var PostSchema = new mongoose.Schema(
rating: type: Number,
upVote: type: Number,
brandId : type: mongoose.Schema.ObjectId, ref: 'Brand',
comment: type: String,
productId: type: mongoose.Schema.ObjectId, ref: 'Style',
styleId: type: mongoose.Schema.ObjectId, ref: 'Style',
photo: type: String
);
我目前正在使用猫鼬填充功能:
exports.productsByBrand = function(req, res)
Product.find(product: req.params.id).populate('style').exec(function(err, products)
res.send(products:products);
);
;
但是,作为菜鸟,这很有效 --- 我已经开始阅读有关 mongoose 填充的性能问题,因为它实际上只是添加了一个额外的查询。
对于我的帖子,尤其是,这似乎很费力。该帖子的目的是成为一个实时的 twitter / instagram 式的提要。似乎可能有很多查询,这可能会大大减慢我的应用程序的速度。
另外,我希望能够在某个时候按字段搜索产品/帖子/品牌。
我是否应该考虑嵌套/嵌入这些数据(产品嵌套/嵌入品牌)?
什么是最有效的架构设计,或者我的设置是否可行——考虑到我指定的用途,我想使用它吗?
用户故事:
会有一个管理员用户。
管理员将能够使用 Brand 架构中的特定字段添加 Brand。
品牌会有相关的产品,每个产品都会有一个风格 / 类别。
搜索:
用户将能够按名称和位置搜索品牌(我正在考虑使用角度过滤/标签来进行此操作)。
用户将能够按字段(名称、样式等)搜索产品。
用户将能够按品牌 产品和风格搜索帖子。
发帖:
用户将能够发帖到Feed。在发帖时,他们会选择一个品牌 和一个 Product 与 Post 相关联。 帖子将显示品牌名称、产品名称和风格——以及新输入的发布 字段(照片、评论和评分)。
其他用户可以点击品牌名称链接到品牌展示页面。他们可以点击产品名称链接到产品展示页面。
产品展示页面:
将显示来自上述架构的 Product 字段——包括来自 Style 架构的关联 Style 名称。它还将显示与特定产品相关的帖子。
品牌展示页面:
将仅显示 品牌 字段和相关产品。
我主要担心的是 Post,它必须填充/查询 Brand、Product 和 Style 在提要中。
再次,我正在考虑是否应该将 Products 嵌入到 Brand 中——那么我是否能够关联 Brand Product 和 Style 以及 Post 以便以后查询?或者,可能是 $lookup 或其他聚合功能。
【问题讨论】:
这应该作为***.com/questions/5373198/…的欺骗而被关闭 @JohnnyHK 我不太确定,因为我们正在谈论 Mongoose 引入的额外复杂性。 数据模型本身只说明了一半(如果有那么多的话)。更重要的是用户故事和/或用例。 MongoDB 中的数据建模从开始,然后您得出数据需要回答的问题,然后仅对数据进行建模。所以为了回答你的问题,应该包括用户故事/用例。 感谢您的反馈@MarkusWMahlberg。我添加了一个简短的用户故事。 【参考方案1】:Mongodb 本身不支持连接。因此,猫鼬填充是对外部参考解析的尝试。 mongodb 的问题是您需要设计数据,以便:
-
大多数查询不需要引用多个集合。
从查询中获取数据后,您无需对其进行过多转换。
考虑所涉及的实体及其关系:
-
品牌就是品牌。不依赖于其他任何东西。
每件产品都属于一个品牌。
每个产品都与一个样式相关联。
每个帖子都与一个产品相关联。
间接地,每个帖子都通过产品与品牌和风格相关联。
现在关于用例:
参考:如果您通过 id 查找一个实体,那么获取 1-2 个相关实体并不是一个很大的开销。
列表:当您必须返回大量对象并且每个对象都需要额外的查询来获取关联对象时。这是一个性能问题。这通常通过一次处理结果集的“页面”来减少,例如每个请求 20 条记录。假设您查询 20 个产品(使用 skip
和 limit
)。对于 20 个产品,您提取两个 id 数组,一个是引用样式,另一个是引用品牌。您使用 $in:[ids]
执行 2 次额外查询,获取品牌和样式对象并将它们放入结果集中。这是每页 3 个查询。用户可以在向下滚动时请求下一页等。
搜索:要搜索产品,还要指定品牌名称和款式名称。可悲的是,产品模型仅包含样式和品牌的 ID。使用品牌和产品搜索帖子时同样的问题。流行的解决方案是维护一个单独的“搜索索引”,一种表格,以完全按照搜索方式存储数据,将所有可搜索字段(如品牌名称、款式名称)放在一个位置。在 mongodb 中手动维护这样的搜索集合可能会很痛苦。这就是ElasticSearch 的用武之地。由于您已经在使用猫鼬,您可以简单地将mongoosastic 添加到您的模型中。 ElasticSearch 的搜索能力远远超过数据库存储引擎所能提供的。
超速:还有一些空间可以加快速度:缓存。附加 mongoose-redis-cache 并提供频繁的重复查询,来自 Redis 的内存中,减少 mongodb 的负载。
Twitter 喜欢 Feed: 现在,如果所有帖子都是公开的,那么按时间顺序为用户列出它们是一个简单的查询。但是,当您引入“社交网络”功能时,情况会发生变化。然后,您需要列出朋友和关注者的“活动源”。关于社交收件箱和扇出列表in mongodb blog 有一些智慧。
故事的寓意是,并非所有用例都只有“数据库模式查询”解决方案。可扩展性就是这样的情况之一。这就是存在其他工具的原因。
【讨论】:
我确实为帖子设置了无限滚动分页设置(如您所建议的那样)。您认为将其与分离的模式一起使用就足够了吗?我对 mongodb 模式的阅读越多,我几乎觉得我应该将 Styles 嵌入到 Brands 中,然后在 Styles 下嵌入相关产品——以利用 NoSQL 预连接。 @NoobSter 是的,您可以嵌入文档,但是您必须在每次更改时更新多个集合中对象的所有副本。随着复杂性的增加,这将变得越来越难以跟踪。另一件事是,一个文档最多只能容纳 16 mb 的数据。因此,您将无法嵌入大量对象。以上是关于构建我的猫鼬模式的最佳方式:嵌入式数组、填充、子文档?的主要内容,如果未能解决你的问题,请参考以下文章
如果用户角色(卖家与买家)有所不同,我该如何构建我的猫鼬模式?