猫鼬:如何避免重复文件?
Mongoose: how to avoid duplicating documents?
我为一些评论设计了一个collection。
评论 collection 架构包含 post 和主题。
帖子属性(关键字,phone,日期,内容,author.name)直接 children 评论 collection。
主题属性(键、标题)是 children 的主题 object,这是 child 的评论 collection。
每个 post 属于一个主题。
每个 post 键都是唯一的,每个主题键都是唯一的。
如果多个 post 属于一个主题,则每次评论都会重复主题数据(NoSQL 不是 ACID,对吧?:-)
问题是:复制主题属性的决定是否正确,或者我应该对 post 和主题使用不同的 collection?
这是我的模型:
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 });
如果您希望避免重复,请为 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);
从这里开始,当您想要插入带有 Topic
的 Review
作为子文档时,请使用 populate()
method。基于您将 author
存储在其自己的文档中这一事实,您可以考虑在那里遵循相同的模式。
我很好奇你对 key
的使用。 MongoDB 默认在顶级文档上创建一个唯一的 _id
,一种主键。如果那是 key
的意图,您可能应该让 MongoDB 处理它。
但归根结底,你的问题没有"correct"解决方案,只有权衡比较。 MongoDB 的一个优点是能够轻松地 "store what you query for",并且由于 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()
的单独模式值得额外查询的权衡。
我为一些评论设计了一个collection。
评论 collection 架构包含 post 和主题。
帖子属性(关键字,phone,日期,内容,author.name)直接 children 评论 collection。
主题属性(键、标题)是 children 的主题 object,这是 child 的评论 collection。
每个 post 属于一个主题。
每个 post 键都是唯一的,每个主题键都是唯一的。
如果多个 post 属于一个主题,则每次评论都会重复主题数据(NoSQL 不是 ACID,对吧?:-)
问题是:复制主题属性的决定是否正确,或者我应该对 post 和主题使用不同的 collection?
这是我的模型:
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 });
如果您希望避免重复,请为 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);
从这里开始,当您想要插入带有 Topic
的 Review
作为子文档时,请使用 populate()
method。基于您将 author
存储在其自己的文档中这一事实,您可以考虑在那里遵循相同的模式。
我很好奇你对 key
的使用。 MongoDB 默认在顶级文档上创建一个唯一的 _id
,一种主键。如果那是 key
的意图,您可能应该让 MongoDB 处理它。
但归根结底,你的问题没有"correct"解决方案,只有权衡比较。 MongoDB 的一个优点是能够轻松地 "store what you query for",并且由于 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()
的单独模式值得额外查询的权衡。