您定义的架构非常好,流程如下。
最初,当用户登录时,您需要向他们显示板列表。这应该很容易,因为您只需使用 board 集合上的 user_id 进行查找查询。
Board.find({members: user_id}) // where user_id is the ID of the user
现在当用户点击特定的板子时,您可以获取带有 board_id 的列表,类似于上面的查询。
List.find({boardId: board_id}) // where board_id is the ID of the board
同样,您可以借助 list_id 和 board_id 获得卡片。
Card.find({boardId: board_id, listId: list_id}) // 其中 board_id 是板子的 ID,listId 是列表的 ID
现在,让我们看看您可能同时需要来自 2 个或更多集合的数据的情况。
例如,当用户点击板时,您不仅需要板中的列表,还需要板中的卡片。
在这种情况下,您需要编写这样的聚合,
Board.aggregate([
// get boards which match a particular user_id
{
$match: {members: user_id}
},
// get lists that match the board_id
{
$lookup:
{
from: 'list',
localField: '_id',
foreignField: 'boardId',
as: 'lists'
}
}
])
这将返回棋盘,在每个棋盘中,都会有一个与该棋盘关联的列表数组。如果一个特定的板没有列表,那么它将有一个空数组。
同样,如果您想将卡片添加到列表和板中,聚合查询将是一个更复杂的机器人,因此,
Board.aggregate([
// get boards which match a particular user_id
{
$match: {members: user_id}
},
// get lists that match the board_id
{
$lookup:
{
from: 'list',
localField: '_id',
foreignField: 'boardId',
as: 'lists'
}
},
// get cards that match the board_id
{
$lookup:
{
from: 'card',
localField: '_id',
foreignField: 'boardId',
as: 'cards'
}
}
])
这也将添加一系列卡片。同样,您也可以获取列表卡片。
现在,让我们考虑一下这是否是最佳架构。我个人认为您建议的架构非常好,因为另一种方法是将 ID 存储在父集合中,这将让您使用填充来获取数据而不是查找查询。
例如,将列表 ID 存储在板集合中。这样做的缺点是,每当添加新列表时,您需要将该列表添加到列表集合中,并且还需要更新列表所连接的板(添加列表 ID),我认为这太繁琐了。
最后,关于您给出的架构的一些建议,
我认为您应该在每个集合中添加 user_id(创建者 ID),因为在很多情况下,您需要显示创建该特定板或列表或其他任何内容的用户的名称,而且因为您具有将用户添加到的功能一张特定的卡片等我认为你应该有两个字段,一个是 creator_id,另一个应该是 associated_users,这将是一个数组(显然你可以选择更好的名称)。
您应该在卡片和其他要按位置排序的集合中添加位置字段。该字段应该是一个数字。
现在删除一张卡片或将其从一个列表移动到另一个列表应该非常简单且不言自明。
修改 1:基于评论
您不需要在聚合“之后”将卡片分配给列表,您可以在聚合本身中执行此操作,所以它会是这样的,
Board.aggregate([
// get boards which match a particular user_id
{
$match: { members: user_id }
},
// get lists that match the board_id
{
$lookup:
{
from: 'list',
localField: '_id',
foreignField: 'boardId',
as: 'lists'
}
},
// unwind lists (because it's an array at the moment)
{
$unwind: '$lists'
},
// Now you have object named lists in every board object
// get cards that match the list_id (note that the cards contain list_id)
{
$lookup:
{
from: 'card',
localField: '_id',
foreignField: 'listId',
as: 'cards'
}
},
// now merge back the objects and get a simple object for each boardID
{
$group: {
_id: "$_id",
members: { $addToSet: "$members" },
lists: { $addToSet: "$lists" }
}
}
])
这会给你这样的东西,
data = {
'_id': '123456',
'members': [
{
name: 'Bob',
_id: '2626'
},
{
name: 'Matthew',
_id: '2627'
}
],
'lists': [
{
name: 'List 1',
_id: '2525',
boardId: '123456',
cards: [
{
name: 'Card 1',
boardId: '123456',
listId: '2525'
},
{
name: 'Card 2',
boardId: '123456',
listId: '2525'
}
]
},
{
name: 'List 2',
_id: '2526',
boardId: '123456',
cards: [
{
name: 'Card 3',
boardId: '123456',
listId: '2525'
},
{
name: 'Card 4',
boardId: '123456',
listId: '2525'
}
]
}
]
}
所以基本上,您可以在单个查询中获取列表和这些列表的卡片,这非常有效。
现在来到你要求的两个查询,
卡片从一个列表移动到另一个列表,只需将卡片文档中的 listId 字段编辑为新的 listID(实际上很简单)。
卡片在列表中上移了一个位置
正如我所说,如果您想要位置,则需要在文档中添加一个名为 position 的字段,然后每当移动卡片时,您都需要更改这些卡片的“位置”值。
在聚合中,您只需要添加另一个名为 '$sort' 的阶段并根据位置值对其进行排序。
这会有点乏味,因为每当您将卡片向上移动时,您也需要更新上方卡片的位置。