【问题标题】: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 更快。

标签: mongodb mongoose mongoose-schema


【解决方案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。

    【讨论】:

    • 这是有道理的。谢谢!
    猜你喜欢
    • 2015-07-28
    • 2017-12-05
    • 1970-01-01
    • 2014-11-12
    • 1970-01-01
    • 2013-10-05
    • 2017-01-26
    • 2015-06-26
    • 2015-10-01
    相关资源
    最近更新 更多