uma*_*air 5 php database-design relational-database mongodb nosql
这个问题适用于所有NoSQL和特别是mongoDB专家.我开始为项目设计关系数据库,但客户希望我们使用可以轻松扩展的数据库.为此,我们决定使用mongoDB.这些天我无法映射我的NoSQL关系模型.我有一个用户表,它与许多其他表有多对多的关系,如下图所示:
转换为mongoDB时我有几个选项:
选项1(用户中有完整的行):
users:{
_id:<user_id>,
battles:{[battle1, battle2, ...]},
items:{[item1, item2, ...]},
locations:{[location1, location2, ...]},
units:{[unit1, unit2, ...]},
}
battles:{
<battle_info>
}
locations:{
<location_info>
}
units:{
<units_info>
}
items:{
<items_info>
}
Run Code Online (Sandbox Code Playgroud)
Option2(用户只有外键):
users:{
_id:<user_id>,
battles:{[battle1_id, battle2_id, ...]},
items:{[item1_id, item2_id, ...]},
locations:{[location1_id, location2_id, ...]},
units:{[unit1_id, unit2_id, ...]},
}
battles:{
<battle_info>
}
locations:{
<location_info>
}
units:{
<units_info>
}
items:{
<items_info>
}
Run Code Online (Sandbox Code Playgroud)
选项3(其他表中的用户ID):
users:{
_id:<user_id>,
}
battles:{
<battle_info>,
user:{[user1_id, user2_id, ...]}
}
locations:{
<location_info>,
user:{[user1_id, user2_id, ...]}
}
units:{
<units_info>,
user:{[user1_id, user2_id, ...]}
}
items:{
<items_info>,
user:{[user1_id, user2_id, ...]}
}
Run Code Online (Sandbox Code Playgroud)
选项1有很多重复,因为我们正在添加其他表的完整行.我在其中看到的一个问题是,如果某个项目或战斗更新,我们将不得不在用户表中找到它的所有出现并更新它们.但是这给了我们一个优势,即始终拥有一个完整的用户对象,可以在登录时将其传递给客户端应用程序.
选项2更具关系性,我们在users表中只有mongoIds的其他表.此选项的优点是更新战斗或项目没有太多成本,因为引用的行未被复制.另一方面,当用户登录时,我们必须找到所有引用的单位,战斗,项目和位置以响应完整的用户对象.
选项3与选项2相反,其中用户表的mongoIds保存在其他表中.这个选项对我没什么吸引力.
我真的很感激有人可以指导我或想出一个更好的模型.
编辑:
基本上这是一个mmorpg游戏,其中多个客户端应用程序将通过Web服务连接到服务器.我们在客户端有一个本地数据库来存储数据.我想要一个模型,服务器可以通过该模型响应完整的用户对象,然后更新或插入客户端应用程序上更改的数据.
首先,NoSQL 不是一刀切.在SQL中,几乎每个1:N和M:N关系都以相同的方式建模.NoSQL的理念是,您对数据建模的方式取决于数据及其使用模式.
其次,我同意Mark Baker:缩放很难,而且它是通过放松约束来实现的.这不是技术问题.我喜欢使用MongoDB,但出于其他原因(不需要编写丑陋的SQL代码;不需要复杂,膨胀的ORM;等等)
现在让我们回顾一下您的选择: 选项1复制的数据超出了需要.您经常需要对某些数据进行非规范化,但绝不会全部归一化.如果是这样,获取引用的对象会更便宜.
选项2/3它们非常相似.关键在于:谁在写作?您不希望很多客户端对同一文档具有写入权限,因为这会强制您使用锁定机制,和/或仅限于修改器操作.因此,选项2可能优于3.但是,如果A攻击B,它们也会触发对用户B的写入,因此您必须确保写入是安全的.
选项4部分非规范化:您的用户对象似乎是最重要的,那么如何:
user {
battles : [ {"Name" : "The battle of foo", "Id" : 4354 }, ... ]
...
}
Run Code Online (Sandbox Code Playgroud)
这样可以更轻松地显示用户仪表板,因为您无需了解仪表板中的所有详细信息.注意:数据结构然后耦合到演示的细节.
选项5边缘数据.通常,关系也需要保存数据:
user {
battles : [ {"Name" : "The battle of foo", "unitsLost" : 54, "Id" : 34354 }, ... ]
}
Run Code Online (Sandbox Code Playgroud)
这里,unitsLost
特定于用户和战斗,因此数据位于图的边缘.与战斗的名称相反,这些数据不是非规范化的.
选项6链接器集合.当然,这种"边缘数据"可能会变得庞大,甚至可能需要一个单独的集合(链接器集合).这完全消除了访问锁定的问题:
user {
"_id" : 3443
}
userBattles {
userId : 3443,
battleId : 4354,
unitsLost : 43,
itemsWon : [ <some list > ],
// much more data
}
Run Code Online (Sandbox Code Playgroud)
其中哪一个最好取决于您的应用程序的许多细节.如果用户进行了大量的点击(即你有一个细粒度的界面),那么分离对象就像选项4或6一样.如果你真的需要一批中的所有数据,那么部分非规范化无济于事,所以选项2会更好.请记住多个作家的问题.
归档时间: |
|
查看次数: |
1548 次 |
最近记录: |