我正在尝试为一个任务管理应用程序设计一个猫鼬方案架构/设计。
期望的功能和模型:
型号:
功能:
- User can add comments to the card
- Card activity logging (On move, on edit, on comment)
我知道它有很多要问的问题,但是如何设计这种功能的方案呢?
孩子父母的引用会是最好的解决方案吗?
例如。
用户:
{
name: 'Bob',
_id: '2626'
}董事会:
{
name: 'Board name',
_id: '123456',
members: [
{ type: ObjectID, ref: 'user' } // '2626'
]
}列表:
{
name: 'List name',
_id: '2525',
boardId: { type: ObjectID, ref: 'board' } // '123456'
}卡:
{
name: 'Card name',
boardId: { type: ObjectID, ref: 'board' } // '123456',
listId: { type: ObjectID, ref: 'list' } // '2525'
}我该如何查询这种结构呢?
因此,对于董事会的观点,我会去抓取所有的名单,但我将不得不去为每个名单的所有卡片,似乎没有真正的效率。
也许,当进入板视图时,我应该只通过板id查询卡片,但是如何获得列表,并将每一张卡放入自己的列表中?
如何处理删除卡片或将卡片从一个列表移到另一个列表?
别对我太苛刻了,我对mongodb世界很陌生,但我真的在尽我最大的努力。
发布于 2019-01-21 13:44:04
您定义的模式非常好,如下所示。
最初,当用户登录时,您需要向他们展示板的列表。这应该很容易,因为您只需对板集合上的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,这将允许您使用填充来获取数据,而不是查找查询。
例如,将列表in存储在板集合中。这样做的缺点是,每当添加新列表时,您都需要在列表集合中添加该列表,并更新列表连接到的板(添加列表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'
}
]
}
]
}因此,基本上,您可以在一个查询本身中获得列表和这些列表的卡片,这是非常有效的。
接下来是你问的两个问题,
正如我所说的,如果您想要这个职位,您需要在文档中添加一个名为position的字段,然后无论何时移动卡片,您都需要更改这些卡片的“位置”的值。在聚合过程中,只需添加另一个名为“$sort”的阶段,并根据位置值对其进行排序。这将是有点乏味,因为无论何时你移动一张卡,你需要更新的位置,上面的卡。
https://stackoverflow.com/questions/54256090
复制相似问题