143

我很好奇在我的主架构中使用子文档与更深层的利弊:

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

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

或者

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

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

4

6 回答 6

84

根据文档,它完全相同。但是,使用模式也会添加一个_id字段(只要您没有禁用该字段),并且可能会使用更多资源来跟踪子文档。

备用声明语法

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

于 2013-05-11T04:53:45.870 回答
43

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

于 2013-09-20T18:20:03.617 回答
29

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

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

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

首先,我们必须考虑为什么我们会想做这样的事情。通常,我会建议人们在获取此文档时嵌入他们总是想取回的东西。这样做的另一面是你不想在文档中嵌入你不想用它回来的东西。

如果你将我执行的活动嵌入到文档中,它一开始会很好用,因为我的所有活动都在那里,只需一次阅读,你就可以取回你可能想向我展示的所有内容:“你最近点击了这个和这里是你的最后两条评论吗?”但是六个月后会发生什么,我不在乎我很久以前做过的事情,除非我专门去寻找一些旧活动,否则你不想向我展示它们?

首先,您最终会返回越来越大的文档并关心其中越来越小的部分。但是你可以使用投影来只返回一些数组,真正的痛苦是磁盘上的文档会变大,即使你只将其中的一部分返回给最终用户,它仍然会被读取,但是因为只要我活跃,我的活动就不会停止,因此文档将继续增长和增长。

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

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

当数组非常适合数据模型时,我不希望这会吓到您使用数组 - 它们是文档数据库数据模型的强大功能,但与所有强大的工具一样,它需要在正确的情况下使用并且应该小心使用。

于 2015-01-09T05:52:29.090 回答
19

基本上,创建一个变量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"
    ]
}

例子:

在此处输入图像描述

于 2016-09-02T15:16:33.813 回答
9

我认为这是由 SO 上的多个帖子在其他地方处理的。

一些:

关键是这里没有单一的答案,只有一组相当复杂的权衡。

于 2013-03-04T22:11:06.363 回答
2

两者有一些区别:

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

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

  • 嵌套模式将“_id”字段添加到子文档,除非您使用“_id:false”
于 2019-11-06T15:28:21.580 回答