如果您希望避免重复,请为 Topic 创建单独的架构,然后在您的 Reviews 中引用它:
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);
从这里,当您想插入带有Topic 的Review 作为子文档时,使用populate() method。基于您将 author 存储在其自己的文档中这一事实,您可以考虑在其中遵循相同的模式。
我很好奇您使用key。默认情况下,MongoDB 在顶级文档上创建一个唯一的_id,这是一种主键。如果这是您对 key 的意图,您可能应该让 MongoDB 处理它。
但归根结底,您的问题没有“正确”的解决方案,只有权衡比较。 MongoDB 的一个优点是能够轻松地“存储您查询的内容”,并且由于 Topics 非常小,如果您每次获取评论时都需要主题,则可能值得重复。 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() 的单独架构值得额外查询的权衡。