猫鼬引用子文档的不同方式?
Posted
技术标签:
【中文标题】猫鼬引用子文档的不同方式?【英文标题】:mongoose different ways to reference subdocuments? 【发布时间】:2019-08-01 10:11:28 【问题描述】:此语法直接来自关于子类型的 mongoose 文档。但是,我也看到了这个对子文档的替代参考。有什么区别?
https://mongoosejs.com/docs/subdocs.html
var childSchema = new Schema( name: 'string' );
var parentSchema = new Schema(
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
);
对子文档的另一种引用方式
var childSchema = new Schema( name: 'string' );
mongoose.model('children', childSchema);
var parentSchema = new Schema(
children:
type: Schema.Types.ObjectId,
ref: 'children'
,
);
【问题讨论】:
是的,所以在第二种情况下,您只是获取文档的 _id 而不是整个文档本身。所以它在文档存储方面要便宜得多,另外,您还可以使用.populate
方法执行类似联接的操作,这比 mongodb 聚合 $lookup
更快。
【参考方案1】:
上述两种语法完全不同,一种是实际的子文档(children)存储在父文档中,另一种是新文档存储在 children 集合中,并且只存储它的引用父文档。
案例 1:
var childSchema = new Schema( name: 'string' );
var parentSchema = new Schema(
// Array of subdocuments
children: [childSchema],
// Single nested subdocuments. Caveat: single nested subdocs only work
// in mongoose >= 4.2.0
child: childSchema
);
在这个给定的语法中,父文档也会将子文档存储在父文档中。
父sollection 中的示例文档将如下所示:
_id : "parent_random_generated_id"
children :[ _id : "childid1" , name : "Captain America",
_id : "childid2" , name : "Iron Man",...],
child : _id : "childid3" , name : "Thor Odinson",
...
案例 2:
var childSchema = new Schema( name: 'string' );
mongoose.model('children', childSchema);
var parentSchema = new Schema(
children:
type: Schema.Types.ObjectId,
ref: 'children'
,
);
在这种语法中,子文档将单独存储,它们的引用id(_id)将存储在父文档中。
本例中的示例文档如下所示:
// Children documents
_id : "childid1" , name : "Captain America"
_id : "childid2" , name : "Iron Man"
_id : "childid3" , name : "Thor Odinson"
//parent document
_id : "parent_random_generated_id"
children :["childid1","childid2",...],
child : "childid3",
...
在第二种情况下,您可以在需要时使用 Mongodb $lookup
运算符填充子文档,使用 mongodb aggregation pipeline
,或使用 .populate('children')
或 .populate('child')
填充特定的子文档。
我希望这能澄清你的疑问。
【讨论】:
感谢您的信息。我假设它们都很快,但第一个示例是不需要次要相关信息的更快搜索查找。可能会出现更多冗余。 是否有任何自动方法可以通过单个调用添加子文档和引用 @ravi-shankar-bharti,或者我应该先“插入”到子文档中,然后再添加对父文档的引用? 【参考方案2】:我已经完成了 Ravi Shankar Bharti 案例 2 带有一些数据写入示例。让我们使用书籍作者的场景:
const authorSchema = new Schema( name: 'string' );
const authorModel = mongoose.model('authors', authorSchema);
const bookSchema = new Schema(
title: String,
author:
type: Schema.Types.ObjectId,
ref: 'author'
,
);
const bookModel = mongoose.model('books', bookSchema)
const authorData = name: "John Doe"
// Check if author does exists. Insert if not or find if yes
const options =
upsert: true,
new: true,
setDefaultsOnInsert: true
;
const anAuthor = await authorModel.findOneAndUpdate(authorData, authorData, options)
// Insert a new book with reference to `anAuthor`
const aBook = new bookModel( title: "MyBook" )
aBook.set( author: anAuthor )
await aBook.save()
在这种语法中,子文档将单独存储,它们的引用id(_id)将存储在父文档中。
本例中的示例文档如下所示:
// authors documents
_id : "authorId1" , name : "John Doe"
_id : "authorId2" , name : "Iron Man"
_id : "authorId3" , name : "Thor Odinson"
//books document
_id : "parent_random_generated_id"
title: "MyBook",
author : "authorId1",
...
而对于阅读,您可以使用populate
:
let result = await bookModel.find()
result = await authorModel.populate(result, path: 'author' )
【讨论】:
【参考方案3】:区别很简单。 您只是为子定义架构的不会为数据库中的子创建单独的集合,而是将整个子文档嵌入到父文档中。
在后面的一个中,您通过调用 mongoose.model 为子架构定义一个模型,这会在数据库中创建一个单独的子架构集合,然后您就可以在父文档中引用子文档,而无需将整个子文档嵌入到父文档中,只需添加子 _id。
【讨论】:
这是有道理的。谢谢!以上是关于猫鼬引用子文档的不同方式?的主要内容,如果未能解决你的问题,请参考以下文章