Mongoose 子文档与嵌套模式

IT技术 javascript node.js mongodb mongoose
2021-03-08 17:18:30

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

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

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

或者

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

我目前在任何地方都使用 subdocs,但我主要想知道我可能遇到的性能或查询问题。

6个回答

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

替代声明语法

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

@DrewGoodwin 是的,mongoose 自动为数组中声明的对象文字创建了一个架构。mongoosejs.com/docs/subdocs.html#altsyntaxarrays
2021-04-29 17:18:30
关于添加 _id 的模式,这是有道理的,但我创建了一个模式,其中包含一组子文档和一组对象文字,并且两者都添加了 _id。行为改变了吗?
2021-05-01 17:18:30
这就是子文档的工作方式。它们嵌入在文档中。在玩 mongoose 之前,请确保您了解底层的 MongoDB。
2021-05-06 17:18:30
@DrewGoodwin 似乎已经有一段时间了:stackoverflow.com/questions/17254008/...
2021-05-09 17:18:30
但我试过这个。为什么子文档数据不存储在单独的集合中。它始终存储在 mainDoc 集合中。
2021-05-14 17:18:30

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

您还应该考虑保存冗余信息的好处/坏处。
2021-05-06 17:18:30
这是一个很好的答案。有时我在多个模型中使用子文档,或者模型中有两个字段需要区分,但仍然具有相同的子文档结构。
2021-05-17 17:18:30

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

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

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

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

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

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

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

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

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

这应该是最佳答案;很划算。MongoDB 自己的白皮书说的差不多。
2021-05-05 17:18:30
这篇关于桶模式的文章对 Asya 所说的很好。 mongodb.com/blog/post/building-with-patterns-the-bucket-pattern我认为 OP 问题中的 subDoc 模式可以很好地与 Bucket Pattern 配合使用。
2021-05-05 17:18:30

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

例子:

在此处输入图片说明

问题不是问如何进行嵌套模式。它讨论了 Mongoose 是否在嵌套模式或嵌入式子文档中性能更高。基本上,我们谈论的是基准测试或分类或边缘情况,其中mongoose更喜欢一种。正如所选答案所提到的,它似乎没有任何区别,至少从 V3 开始是这样。
2021-05-02 17:18:30
这根本没有解决性能问题。
2021-05-11 17:18:30
也许不适用于 OP,但我发现这非常有帮助。谢谢。
2021-05-13 17:18:30
为了更有意义,我编辑了一些。你怎么认为?
2021-05-17 17:18:30
当所有 3 个模式都在一个 .js 文件中声明时,这很好,当在 3 个不同的 .js 文件中声明时,我们如何处理它?
2021-05-17 17:18:30

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

一些:

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

也许我没有正确表达我的问题 - 这不是我应该如何构建我的数据库的问题,而是使用子模式与仅在更深层编写数组的内部结构的问题。我使用子模式的主要原因是我可以使用自定义模式类型并让它们验证 - 这不适用于嵌套数组(来自我之前关于 SO 的问题)。就我所知,子文档与嵌套数组几乎相同 - 我只是不知道它的内部结构 - 如果使用它们会产生性能问题等。
2021-05-17 17:18:30