构建我的mongoose模式的最佳方法:嵌入式数组,填充,子文档?

Noo*_*ter 8 mongoose mongodb nosql node.js

这是我目前的架构

牌:

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 }
  }
});
Run Code Online (Sandbox Code Playgroud)

样式:

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

var StyleSchema = new mongoose.Schema({
  name: { type: String, lowercase: true , required: true},
});
Run Code Online (Sandbox Code Playgroud)

产品

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}
});
Run Code Online (Sandbox Code Playgroud)

帖子:

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}
});
Run Code Online (Sandbox Code Playgroud)

我目前正在使用mongoose populate功能:

exports.productsByBrand = function(req, res){
  Product.find({product: req.params.id}).populate('style').exec(function(err, products){
    res.send({products:products});
  });
};
Run Code Online (Sandbox Code Playgroud)

然而,这是一个菜鸟 - 我已经开始阅读有关mongoose populate的性能问题,因为它实际上只是添加了一个额外的查询.

特别是对于我的帖子来说,似乎可能很费力.这篇文章的目的是成为一个真实的推特/ Instagram类似的饲料.似乎可能是很多查询,这可能会大大减慢我的应用程序.

此外,我希望能够在某些时候按字段搜索产品/帖子/品牌.

我应该考虑嵌套/嵌入这些数据(嵌套/嵌入品牌的产品)吗?

什么是最有效的架构设计或我的设置是否正常 - 鉴于我已指定我想用它?


用户故事:

将有一个管理员用户.

管理员将能够添加品牌与在特定领域的品牌架构.

品牌将有相关的产品,每个产品将有一个样式 /类别.


搜索:

用户将能够按名称和位置搜索品牌(我正在考虑使用角度过滤/标签进行此操作).

用户将能够按字段(名称,样式等)搜索产品.

用户将能够搜索通过品牌 产品风格.


帖子:

用户将能够发布Feed中.在制作帖子时,他们会选择一个品牌和一个产品来关联帖子.该帖子将显示品牌名称,产品名称,样式与新输入的沿- 场(照片,评论,评分).

其他用户可以点击品牌名称链接到品牌展示页面.他们可以单击产品名称以链接到产品展示页面.

产品展示页面:

将显示上述架构中的产品字段 - 包括样式架构中的关联样式名称.它还将显示与特定产品相关的帖子.

品牌展示页面:

将简单地显示品牌字段和相关产品.


我主要担心的是Post,它必须填充/查询Feed中的品牌,产品样式.

同样,我考虑我是否应该嵌入产品的内部品牌 -那么我将能够给联想品牌 产品风格邮政供以后查询?或者,可能是$ lookup或其他聚合功能.

S.D*_*.D. 6

Mongodb本身不支持连接.所以,mongoose populate是一种外部参考分辨率的尝试.使用mongodb的是你需要设计你的数据,以便:

  1. 大多数查询都不需要引用多个集合.
  2. 从查询中获取数据后,您无需进行太多转换.

考虑所涉及的实体及其关系:

  1. 品牌是品牌.不依赖于其他任何东西.
  2. 每个产品都属于一个品牌.
  3. 每个产品都与样式相关联.
  4. 每个帖子都与产品相关联.
  5. 间接地,每个帖子都通过产品与品牌和风格相关联.

关于用例:

  1. 请参阅:如果您通过id查找一个实体,那么获取1-2个相关实体并不是一个很大的开销.

  2. 列表:当您必须返回大量对象时,每个对象都需要一个额外的查询来获取关联对象.这是一个性能问题.这通常通过一次处理结果集的"页面"来减少,例如每个请求20个记录.让我们假设您查询20个产品(使用skiplimit).对于20种产品,您可以提取两个id数组,一个引用的样式,以及其他引用的品牌.您使用$in:[ids]获取2个其他查询,获取品牌和样式对象并将它们放在结果集中.这是每页3个查询.用户可以在向下滚动时请求下一页,依此类推.

  3. 搜索:您想要搜索产品,但也想要指定品牌名称和样式名称.可悲的是,产品型号只适用于款式和品牌.与品牌和产品一起搜索帖子的问题相同.流行的解决方案是维护一个单独的"搜索索引",一种表格,它可以准确地存储数据的搜索方式,并在一个地方显示所有可搜索的字段(如品牌名称,样式名称).手动维护mongodb中的搜索集合可能会很麻烦.这就是ElasticSearch的用武之地.由于你已经在使用mongoose,你可以简单地将mongoosastic添加到你的模型中.ElasticSearch的搜索功能远远超过数据库存储引擎为您提供的功能.

  4. 超速:还有一些加速的空间:缓存.附加mongoose-redis-cache并在Redis内存中频繁重复查询,减少mongodb的负载.

  5. Twitter喜欢Feeds:现在如果所有帖子都是公开的,那么按时间顺序为用户列出它们是一个简单的查询.但是,当您引入"社交网络"功能时,情况会发生变化 然后,您需要列出朋友和关注者的"活动源".在mongodb博客中有关于社交收件箱和扇出列表的一些智慧.

故事的道德是并非所有用例都只有"db schema query"解决方案.可伸缩性就是这种情况之一.这就是为什么存在其他工具的原因.