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

时间:2016-05-27 19:48:50

标签: node.js mongodb mongoose nosql

这是我目前的Schema

品牌:

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}
});

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

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

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

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

另外,我希望能够在某些时候按字段搜索prodcuts / post / brand。

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

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

用户故事:

会有管理员用户。

管理员可以使用品牌架构中的特定字段添加品牌

品牌将有关联的产品,每个产品将具有样式 /类别。

搜索:

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

用户可以按字段(名称,样式等)搜索产品

用户可以通过品牌 产品样式搜索发布

发布:

用户可以发布 Feed中。在制作发布时,他们会选择品牌产品帖子与之关联。 帖子将显示品牌名称,产品名称和样式 - 以及新输入的发布字段(照片,评论和评级)。

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

产品展示页

将显示上述架构中的产品字段 - 包括 Style 架构中的关联样式名称。它还会显示与特定产品相关的发布

品牌展示页面:

将只显示品牌字段和相关产品。

我主要担心的是帖子,它必须填充/查询品牌产品 Style < / em>在Feed中。

同样,我正在考虑是否应将产品嵌入品牌中 - 然后我能够关联品牌 产品样式发布以供日后查询?或者,可能是$ lookup或其他聚合功能。

1 个答案:

答案 0 :(得分:6)

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

  1. 您的大多数查询都不需要引用多个集合。
  2. 从查询中获取数据后,您无需对其进行过多的转换。
  3. 考虑所涉及的实体及其关系:

    1. 品牌是品牌。不依赖于其他任何东西。
    2. 每件产品都属于一个品牌。
    3. 每件商品都与款式相关联。
    4. 每篇博文都与产品相关联。
    5. 间接地,每个帖子都通过产品与品牌和风格相关联。
    6. 现在关于用例:

      1. 参考:如果您按ID查找一个实体,那么获取1-2个相关实体并不是一个很大的开销。

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

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

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

      5. Twitter喜欢Feeds:现在,如果所有帖子都是公开的,那么按时间顺序为用户列出它们是一个简单的查询。然而,当你介绍&#34;社交网络&#34;特征。然后你需要列出&#34;活动源&#34;的朋友和追随者。关于社交收件箱和扇出列表in mongodb blog有一些智慧。

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