Mongodb 子文档结构最佳实践和查询

Mongodb subdocument structure best practices and queries

我见过 2 种主要的子文档架构类型:

{
    "cbill@boogiemail:com": {
        "outbound": [
            {
                "name": "First",
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "active"
                },
                "data": {
                }
            },
            {
                "name": "Second",
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "draft"
                },
                "data": {
                }
            }
        ],
        "inbound" : [
            {
                "name": "First",
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "active"
                },
                "data": {
                }
            },
            {
                "name": "Second",
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "draft"
                },
                "data": {
                }
            }
        ]
    }
}

替代结构是:

{
    "cbill@boogiemail:com": {
        "outbound": {
            "First": {
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "active"
                },
                "data": {
                }
            },
            "Second": {
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "draft"
                },
                "data": {
                }
            }
        },
        "inbound" : {
            "First": {
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "active"
                },
                "data": {
                }
            },
            "Second": {
                "state": {
                    "saved": "cbill@boogiemail.com",
                    "edited": "connie@boogiemail.com",
                    "status": "draft"
                },
                "data": {
                }
            }
        }
    }
}

两者的主要区别在于 inbound/outbound 子文档的结构。

Mongo 数据库子文档结构的最佳实践是什么? 在每种情况下,什么样的查询会让我得到指向的子文档:

cbill@boogiemail:com.inbound.Second ?

要添加更多信息:

该集合将包含许多以不同电子邮件地址开头的不同文档,但集合中的每个文档在 inbound/outbound 键下只有几个子文档。

您希望以反映您打算如何使用数据的方式构建您的集合和文档。如果您要执行大量复杂查询,尤其是子文档查询,您可能会发现将文档拆分为单独的集合会更容易。这方面的一个例子是从博客 posts.

中拆分评论

您的评论可以存储为子文档数组:

# Example post document with comment subdocuments
{
    title: 'How to Mongo!'
    content: 'So I want to talk about MongoDB.',
    comments: [
        {
            author: 'Renold',
            content: 'This post, it's amazing.'
        },
        ...
    ]
}

不过,如果您只想对评论进行复杂查询(例如,从所有 post 中选取最新评论或获取一位作者的所有评论),这可能会导致问题。进行这些复杂的查询时,您最好创建两个集合:一个用于评论,另一个用于 posts.

# Example post document with "ForeignKeys" to comment documents
{
    _id: ObjectId("50c21579c5f2c80000000000"),
    title: 'How to Mongo!',
    content: 'So I want to talk about MongoDB.',
    comments: [
        ObjectId("50c21579c5f2c80000000001"),
        ObjectId("50c21579c5f2c80000000002"),
        ...
    ]
}

# Example comment document with a "ForeignKey" to a post document
{
    _id: ObjectId("50c21579c5f2c80000000001"),
    post_id: ObjectId("50c21579c5f2c80000000000"),
    title: 'Renold',
    content: 'This post, it's amazing.'
}

这类似于您在关系数据库中存储“外键”的方式。像这样规范化您的文档使得查询评论和 posts 变得容易。此外,由于您正在拆分文档,因此每个文档占用的内存也会减少。但是,trade-off 是您必须在任一文档发生更改时维护 ObjectId 引用(例如,当您 insert/update/delete 评论或 post。)并且因为那里Mongo 中没有事件挂钩,您必须在您的应用程序中进行所有这些维护。

在 other-hand 上,如果您不打算对文档的子文档执行任何复杂查询,您可能会受益于存储整体对象。例如,您可能不会查询用户的偏好:

# Example user document with address subdocument
{
    ObjectId("50c21579c5f2c800000000421"),
    name: 'Howard',
    password: 'naughtysecret',
    address: {
        state: 'FL',
        city: 'Gainesville',
        zip: 32608
    }
}

稍作修改后从此处 (https://www.tutorialspoint.com/how-to-select-a-specific-subdocument-in-mongodb) 找到答案。

第二个示例(我最感兴趣的那个)的查询是:

find({ "cbill@boogiemail:com.inbound": {$exists: true}},{"cbill@boogiemail:com.inbound.Second":1}).pretty()

这导致:

{
    "_id" : ObjectId("6216a9940b84b1a642cb925e"),
    "cbill@boogiemail:com" : {
        "inbound" : {
            "Second" : {
                "state" : {
                    "saved" : "cbill@boogiemail.com",
                    "edited" : "connie@boogiemail.com",
                    "status" : "draft"
                },
                "data" : {
                    
                }
            }
        }
    }
}

我不确定这是否是最有效的查询 - 欢迎 post 任何更好的选择。