在Mongodb中嵌入或引用

时间:2013-08-06 13:15:36

标签: mongodb nosql

我正在开发一个小应用程序,它将存储有关用户,帐户和交易的信息。用户将拥有许多帐户(可能少于10个),并且帐户将有许多交易(可能是1000个)。阅读文档似乎表明嵌入如下是... ...

{
"username": "joe",
"accounts": [
    {
        "name": "account1",
        "transactions": [
            {
                "date": "2013-08-06",
                "desc": "transaction1",
                "amount": "123.45"
            },
            {
                "date": "2013-08-07",
                "desc": "transaction2",
                "amount": "123.45"
            },
            {
                "date": "2013-08-08",
                "desc": "transaction3",
                "amount": "123.45"
            }
        ]
    },
    {
        "name": "account2",
        "transactions": [
            {
                "date": "2013-08-06",
                "desc": "transaction1",
                "amount": "123.45"
            },
            {
                "date": "2013-08-07",
                "desc": "transaction2",
                "amount": "123.45"
            },
            {
                "date": "2013-08-08",
                "desc": "transaction3",
                "amount": "123.45"
            }
        ]
    }
 ]
}

我的问题是......由于事务列表将在文档中增长到大约1000个,因此数据将变得支离破碎并降低性能。我是否更好地拥有一个文档来存储用户和不会增长的帐户,然后是一个单独的集合来存储引用帐户的事务。或者,还有更好的方法?

4 个答案:

答案 0 :(得分:6)

这不是要走的路。你有很多交易,你不知道你会得到多少。而不是这样,你应该存储它们:

{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-07",
    "desc": "transaction2",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account1",
    "date": "2013-08-08",
    "desc": "transaction3",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-07",
    "desc": "transaction2",
    "amount": "123.45"
},
{
    "username": "joe",
    "name": "account2",
    "date": "2013-08-08",
    "desc": "transaction3",
    "amount": "123.45"
}

在像MongoDB这样的NoSQL数据库中,你不应该害怕反规范化。正如您所注意到的,我甚至没有为用户打扰过单独的收藏。如果您的用户拥有每次交易必须显示的更多信息,您可能还需要考虑包含该信息。

如果您需要搜索或选择任何这些字段,请不要忘记创建索引,例如:

// look up all transactions for an account
db.transactions.ensureIndex( { username: 1, name: 1 } ); 

// look up all transactions for "2013-08-06"
db.transactions.ensureIndex( { date: 1 } ); 

复制数据有很多好处。使用上面的模式,您可以拥有尽可能多的事务,并且您永远不会得到任何碎片,因为文档永远不会更改 - 您只需添加它们。这也提高了写入性能,并使其他查询更容易。

<强>替代

另一种选择可能是将用户名/名称存储在集合中,并仅将其ID与事务一起使用:

账户:

{
    "username": "joe",
    "name": "account1",
    "account_id": 42,
}

交易:

{
    "account_id": 42,
    "date": "2013-08-06",
    "desc": "transaction1",
    "amount": "123.45"
},

这会创建较小的交易文档,但它确实意味着您必须执行两个查询以获取用户信息。

答案 1 :(得分:1)

  

由于事务列表将在文档中增长到大约1000个,因此数据将变得支离破碎并降低性能。

几乎可以肯定的是,如果在一段时间内交易只达到数千而不是10千分之一的单一账户,我会感到惊讶。

添加了您将从不断增长的文档中看到的碎片级别随着时间的推移您可能会遇到严重问题,如果没有用完根文档空间(它是16meg)。事实上,考虑到您将一个人的所有帐户存储在一个文档下的事实,我会说您在大约2年的时间内填写文档的风险很高。

我会参考这种关系。

答案 2 :(得分:1)

我会将交易分成不同的集合。似乎用户和交易之间的数据和更新模式是完全不同的。如果事务不断添加到用户并导致它一直在增长,那么它将在mongo文件中大​​量移动。所以,是的,它会带来性能影响(碎片化,更多IO,更多mongo工作)。 此外,数组操作性能有时会在文档中的大数组上取消分离,因此在数组中保存1000个对象可能不是一个好主意(取决于您使用它做什么)。

答案 3 :(得分:0)

您应该考虑使用ensureIndex()函数创建索引,它应该降低性能问题的风险。 添加这些内容越早,您就越能理解集合的结构。 我没有使用mongo太长时间,但我没有遇到任何问题(尚未解决)数据碎片

编辑如果您打算将其用于多对象提交,则mongo不支持回滚。您需要使用64位版本来允许日记并使事务持久。