猫鼬:如何避免重复文件?

时间:2016-04-04 21:36:32

标签: mongodb mongoose database-schema nosql

我为一些评论设计了一个集合 审阅集合架构包含帖子和主题 帖子属性(密钥,电话,日期,内容,作者姓名)是评论集的直接子项 主题属性(键,标题)是主题对象的子项,它是审阅集合的子项 每个帖子都属于一个主题 每个帖子键都是唯一的,每个主题键都是唯一的 如果许多帖子属于某个主题,则每次审核都会重复主题数据(NoSQL不是ACID,对吧?: - )

问题是:重复主题属性的决定是正确的,还是我应该为帖子和主题使用不同的集合?

这是我的模特:

var reviewSchema = new mongoose.Schema({
  key: String,
  phone: String,
  date: Date,
  contents: String,
  author: {
    name: String,
  },
  topic: {
    key: String,
    title: String,
  },
});
reviewSchema.index({ 'key': 1 }, { unique: true });
reviewSchema.index({ 'phone': 1 }, { unique: false });
reviewSchema.index({ 'topic.key': 1 }, { unique: false });

1 个答案:

答案 0 :(得分:4)

如果您希望避免重复,请为Topic创建单独的架构,然后在Review中引用它:

var TopicSchema = new mongoose.Schema({
    key: String,
    title: String
});

var ReviewSchema = new mongoose.Schema({
    key: String,
    phone: String,
    ...
    topic: {type: Schema.Types.ObjectId, ref: 'Topic'}
});

var Topic = mongoose.model('Topic', TopicSchema);
var Review = mongoose.model('Review', ReviewSchema);

从此处开始,当您要插入populate() Review作为子文档时,请使用Topic method。基于您将author存储在自己的文档中的事实,您可以考虑在那里遵循相同的模式。

我很好奇你使用key。默认情况下,MongoDB在顶级文档(一种主键)上创建一个唯一的_id。如果那是你key的意图,你应该让MongoDB处理它。

但是在一天结束时,你的问题没有“正确”的解决方案,只是比较权衡。 MongoDB的一个优点是能够轻松地“存储您查询的内容”,并且由于Topic非常小,如果您每次获取评论时都需要主题,则可能值得重复。 MongoDB不是集合中的ACID(我不能代表其他NoSQL选项),因此使用这种方法,一次更新所有嵌入的主题可能会导致用户出现短暂的差异。

// Get entire review in one go, including subdocuments!
Review.findOne( { "key": "myReview" }, (err, doc) => { /* do things */ } );

// On bulk topic updates, not all topics change at once (not ACIDic)
Review.update(
  { topic.title: 'foo' },
  { topic.title: 'bar' },
  { multi: true },
  (err, doc) => {/* callback */ }
);

如果您来自SQL背景,上面描述的populate()范例会感觉更舒服。由于MongoDB是每个文档的ACIDic,因此更新主题一次就足以引用它的所有其他文档。在幕后,这将要求Mongoose至少进行两次查询:一次针对Review,然后再针对引用的Topic

// To replace refs with documents two queries behind the scenes
Review.findOne( { key: 'myReview' } )
  .populate('topic').exec( (err, review) => { /* do things */ })

// But updating a single topic is ACIDic, since reviews only contain references
Topic.update( { key: 'foo' }, { title: 'sci-fi' }, (err, res) => {/* more stuff */ } )

根据我的经验,除非您将查询管道推到极限并希望不惜一切代价缩短响应时间,否则使用populate()的单独模式值得额外查询的权衡。