example
-
User
集合(aka nodes使用适当的图论术语)和
Friendship
集合(又名边)
-
每个
用户
friends
数组,其每个元素包含每个朋友的ObjectID。每个元素还可以缓存关于每个朋友的只读信息(例如姓名、照片URL),这样可以避免对常见用例(如“display my friend list”)进行跨文档查询。
-
添加友谊需要插入一个新的
友谊
记录然后
$push
-在
友谊
的对象ID
我在考虑一个不同的设计
友谊
集合时,边缘数据将存储(复制)在双向关系的两个节点中。这样地:
{
_id: new ObjectID("111111111111111111111111"),
name: "Joe",
pictureUrl: "https://foo.com/joe.jpg",
invites: [
... // similar schema to friends array below
],
friends: [
{
friendshipId: new ObjectID("123456789012345678901234"),
lastMeeting: new Date("2019-02-07T20:35:55.256+00:00"),
user1: {
userId: new ObjectID("111111111111111111111111"),
name: "Joe", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/joe.jpg",
},
user2: {
userId: new ObjectID("222222222222222222222222"),
name: "Bill", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/bill.jpg",
},
}
]
},
{
_id: new ObjectID("222222222222222222222222"),
name: "Bill",
pictureUrl: "https://foo.com/bill.jpg",
invites: [
... // similar schema to friends array below
],
friends: [
{
friendshipId: new ObjectID("123456789012345678901234"),
lastMeeting: new Date("2019-02-07T20:35:55.256+00:00"), // shared data about the edge
user1: { // data specific to each friend
userId: new ObjectID("111111111111111111111111"),
name: "Joe", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/joe.jpg",
},
user2: { // data specific to each friend
userId: new ObjectID("222222222222222222222222"),
name: "Bill", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/bill.jpg",
},
}
]
}
以下是我计划如何处理以下问题:
-
用户
数组。
-
邀请朋友-将新文档添加到
invites
在结构和功能上与
朋友
上面显示的集合
-
已接受邀请-使用
updateMany
朋友
两个用户的数组,以及
$pull
元素来自
邀请
两个用户的数组。最初,我将使用多文档事务处理这些更新,但由于添加友谊不是时间关键,因此可以对其进行调整以使用最终的一致性。
-
更新名称
带过滤器
{'friends.friendshipId': new ObjectID("123456789012345678901234")}
到
$拉
来自两个用户的友谊子文档
朋友
数组。与上面一样,这可以在开始时使用多文档事务,如果需要扩展,则最终使用一致性。
-
朋友
(例如,名称或图片URL),这是一个不常见的操作,它可以缓慢地一次处理一个文档,因此最终的一致性是可以的。
我有两个基本问题需要你的建议:
-
上述方法存在哪些问题和陷阱?我知道一些显而易见的事情:额外的存储、较慢的更新、需要添加队列和重试逻辑以支持最终的一致性,以及边缘数据在两个副本之间不同步的风险。我想我对这些问题没意见。但是,还有其他不明显的问题,我可能会遇到吗?
-
而不是
user1
和
user2
字段对于边缘的每个节点,使用2元素数组是否更好?为什么或者为什么不呢?我的意思是:
friends: [
{
friendshipId: new ObjectID("123456789012345678901234"),
lastMeeting: new Date("2019-02-07T20:35:55.256+00:00"),
users: [
{
userId: new ObjectID("111111111111111111111111"),
name: "Joe", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/joe.jpg",
},
{
userId: new ObjectID("222222222222222222222222"),
name: "Bill", // cached, read-only data to avoid multi-doc reads
pictureUrl: "https://foo.com/bill.jpg",
},
],
}
]
顺便说一句,我知道与MongoDB相比,图形数据库甚至关系数据库更擅长于建模关系。但是由于各种原因,我现在已经决定使用MongoDB,所以请限制对MongoDB解决方案的回答,而不是让我使用图形或关系数据库。谢谢!