猫鼬子文档与嵌套模式


122

我对在主模式中使用子文档和更深层的优缺点感到好奇:

var subDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [subDoc]
});

要么

var mainDoc = new Schema({
  names: [{
    name: String
 }]
});

我目前在各处使用子文档,但是我主要想知道性能或查询我可能遇到的问题。


我试图输入一个答案给您,但我找不到方法。但给看看这里:mongoosejs.com/docs/subdocs.html
gustavohenke

以下是有关MongoDB的考虑了不错的反响创建数据库架构时要问自己:stackoverflow.com/questions/5373198/...
anthonylawson

您是说还需要描述该_id字段吗?我的意思是,如果启用它不是自动的吗?
Vadorequest 2014年

有人知道_id子文档的字段是否唯一吗?(在OP的问题中使用第二种方式创建)
琦玉

Answers:


72

根据文档,它是完全一样的。但是,使用Schema也会添加一个_id字段(只要您没有禁用该字段),并且大概会使用更多资源来跟踪子文档。

备用声明语法

v3中的新增功能如果不需要访问子文档架构实例,则还可以通过简单地传递对象文字来声明子文档[...]


1
但是我尝试过了。为什么子文档数据没有存储在单独的集合中。它始终存储在mainDoc集合中。
费扎尔汗

17
这就是子文档的工作方式。它们嵌入文档中。在玩猫鼬之前,请确保您了解底层的MongoDB。
AndyL

1
关于添加_id的模式,这是有道理的,但是我创建了一个包含子文档数组和对象文字数组的模式,并且都向其中添加了_id。行为改变了吗?
德鲁·古德温

@DrewGoodwin好像已经有一段时间了:stackoverflow.com/questions/17254008/…–
cheesemacfly

37

如果您有在模型的各个部分中重复使用的架构,则为子文档定义单个架构可能会很有用,这样您就不必重复自己了。


4
这是一个很好的答案。有时,我会在一个以上的模型中使用子文档,或者在模型中有两个字段需要区分,但是仍然具有相同的子文档结构。
MartinHallén2014年

2
您还应该考虑保存冗余信息的优点/缺点。
Sam Vloeberghs 2014年

25

如果嵌入文档是静态文档,或者由于性能影响不超过几百个,则应使用嵌入文档。我已经解决了一段时间了。最近,作为MongoDB解决方案架构师的Asya Kamsky写了一篇有关“使用子文档”的文章。

我希望这对寻求解决方案或最佳实践的人有所帮助。

原始帖子位于http://askasya.com/post/largeembeddedarrays。您可以在https://stackoverflow.com/users/431012/asya-kamsky上找到她的stackoverflow个人资料

首先,我们必须考虑为什么要这样做。通常,我建议人们在获取此文档时嵌入他们一直想要取回的东西。不利的一面是,您不想将不需要的内容嵌入文档中。

如果您将我执行的活动嵌入文档中,那么起初效果会很好,因为我所有的活动都在那里,只需阅读一遍,您就可以取回您可能想要显示的所有内容:“您最近在此处单击了此处是您的最后两个评论”,但是六个月后会发生什么,我不在乎我很久以前所做的事情,除非我专门去寻找一些旧活动,否则您不想向我展示它们?

首先,您最终将返回越来越大的文档,并关心其中越来越少的部分。但是您可以使用投影仅返回一些数组,真正的痛苦是磁盘上的文档将变得更大,即使您只打算将部分文档返回给最终用户,它仍将被全部读取,但是由于只要我处于活动状态,我的活动就不会停止,因此该文档将继续增长。

最明显的问题是,最终您将达到16MB的文档限制,但这根本不是您应该关注的问题。不断增长的文档每次必须将其重新放置在磁盘上时,都会招致越来越高的成本,即使您采取措施减轻碎片的影响,您的写入总体上也将不必要地长,从而影响整个应用程序的整体性能。

您还可以做一件事,那将完全破坏应用程序的性能,并且将这个不断增加的数组编入索引。这意味着每次重新定位具有此数组的文档时,需要更新的索引条目的数量都与该文档中的索引值的数量成正比,并且数组越大,该数量将越大是。

我不希望这使您害怕在数组非常适合数据模型时使用它们-它们是文档数据库数据模型的强大功能,但是像所有强大的工具一样,需要在正确的情况下使用它并且应谨慎使用。


3
这应该是最佳答案。这真是钱。MongoDB自己的白皮书说的差不多。
杰伊·爱德华兹

关于存储桶模式的这篇文章很好地补充了Asya所说的内容。 mongodb.com/blog/post/building-with-patterns-the-bucket-pattern我认为OP问题中的subDoc模式可以与Bucket Pattern很好地配合。
plong0

13

基本上,创建一个变量nestedDov并将其放在此处name: [nestedDov]

简单版本:

var nestedDoc = new Schema({
  name: String
});

var mainDoc = new Schema({
  names: [nestedDoc]
});

JSON范例

{
    "_id" : ObjectId("57c88bf5818e70007dc72e85"),
    "name" : "Corinthia Hotel Budapest",
    "stars" : 5,
    "description" : "The 5-star Corinthia Hotel Budapest on the Grand Boulevard offers free access to its Royal Spa",
    "photos" : [
        "/photos/hotel/corinthiahotelbudapest/1.jpg",
        "/photos/hotel/corinthiahotelbudapest/2.jpg"
    ],
    "currency" : "HUF",
    "rooms" : [
        {
            "type" : "Superior Double or Twin Room",
            "number" : 20,
            "description" : "These are some great rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/2.jpg",
                "/photos/room/corinthiahotelbudapest/5.jpg"
            ],
            "price" : 73000
        },
        {
            "type" : "Deluxe Double Room",
            "number" : 50,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 92000
        },
        {
            "type" : "Executive Double Room",
            "number" : 25,
            "description" : "These are amazing rooms",
            "photos" : [
                "/photos/room/corinthiahotelbudapest/4.jpg",
                "/photos/room/corinthiahotelbudapest/6.jpg"
            ],
            "price" : 112000
        }
    ],
    "reviews" : [
        {
            "name" : "Tamas",
            "id" : "/user/tamas.json",
            "review" : "Great hotel",
            "rating" : 4
        }
    ],
    "services" : [
        "Room service",
        "Airport shuttle (surcharge)",
        "24-hour front desk",
        "Currency exchange",
        "Tour desk"
    ]
}

例:

在此处输入图片说明


1
这根本解决不了性能问题。
cyberwombat

我进行了一些编辑,以使其更具意义。你怎么看?
韦恩邱

3
问题不在于如何进行嵌套模式。它讨论了在嵌套模式或嵌入式子文档中Mongoose是否更高效。基本上,我们在谈论基准,排序或边缘情况,猫鼬优先选择一种。正如所选答案所提到的,至少从V3开始,它似乎没有任何区别。
cyberwombat

17
也许不适用于OP,但我发现这很有帮助。谢谢。
Gene Higgins

当在一个.js文件中声明所有3个模式时,这很好,当在3个不同的.js文件中声明时,如何处理呢?
萨蒂扬

9

我认为这是在SO上的多个帖子中处理的。

一些:

最大的关键是这里没有一个单一的答案,只有一系列相当复杂的权衡。


3
也许我没有正确表达我的问题-这不是我应该如何构建数据库的问题,而是关于使用子模式而不是在更深层中编写数组的内部问题。我使用子模式的主要原因是,我可以利用自定义架构类型并对其进行验证-这不适用于嵌套数组(来自我之前对SO提出的问题)。据我所知,子文档与嵌套数组几乎相同-我只是不知道它的内部-如果使用它们会导致性能问题或类似问题。
cyberwombat 2013年

0

两者之间有一些区别:

  • 使用嵌套模式有助于验证。

  • 嵌套模式可以在其他模式中重用。

  • 嵌套模式将'_id'字段添加到子文档中,除非您使用了“ _id:false”
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.