Mongoose/Mongodb 类似 trello 的基本方案问题,在 vue 中呈现

Posted

技术标签:

【中文标题】Mongoose/Mongodb 类似 trello 的基本方案问题,在 vue 中呈现【英文标题】:Mongoose/Mongodb basic trello like scheme problem with rendering in vue 【发布时间】:2019-06-30 04:55:50 【问题描述】:

我正在创建一个非常基本的功能看板。

到目前为止,我的板子有 4 个模型:

用户模型

var userSchema = new Schema(
  name: 
    type: String,
    required: true
  
)

module.exports = mongoose.model('User', userSchema)

板模型

var boardSchema = new Schema(
  title: 
    type: String,
    required: true
  ,
  lists: [ listSchema ]
  members: [
    
      type: Schema.Types.ObjectId,
      ref: 'user'
    
  ]
);

module.exports = mongoose.model('Board', boardSchema)

列表架构

let listSchema = new Schema(
  title: 
    type: String,
    required: true
  ,
  userCreated: 
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'user'
  ,
  boardId: 
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'board'
  ,
  sort: 
    type: Number,
    decimal: true,
    required: true
  
)

module.exports = mongoose.model('List', listSchema)

卡片架构

var cardSchema = new Schema(
  title: 
    type: String,
    required: true
  ,
  description: 
    type: String
  ,
  boardId: 
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'board'
  ,
  listId: 
    type: Schema.Types.ObjectId,
    required: true,
    ref: 'list'
  ,
  members: [
    
      type: Schema.Types.ObjectId,
      ref: 'user'
    
  ],
  sort: 
    type: Number,
    decimal: true,
    required: true
  
)

module.exports = mongoose.model('Card', cardSchema)

我在寻找什么?

我的前端是用 Vue.js 和 sortable.js 拖放库制作的。

我想找到用列表(列)和卡片在其中呈现板的最佳方法。

据我了解,我应该首先通过成员数组中的用户 ID 获取我的董事会。

然后我的板子已经嵌入了列表。

在第二个 api 请求中,我通过 boardId 获取所有卡片。

我的问题是 - 我如何正确地将所有卡片放入/渲染到每个拥有列表中?

所以最后我想要这样的东西:


  title: 'My board',
  lists: [
    
      title: 'My list',
      _id: '35jj3j532jj'
      cards: [
       
        title: 'my card',
        listId: '35jj3j532jj'
       
      ]
    ,
    
      title: 'My list 2',
      _id: '4gfdg5454dfg'
      cards: [
       
        title: 'my card 22',
        listId: '4gfdg5454dfg'
       ,
       
        title: 'my card 22',
        listId: '4gfdg5454dfg'
       
      ]
    
  ]
  members: [
    'df76g7gh7gf86889gf989fdg'
  ]

我尝试了什么?

到目前为止,我只想到了一件事,那就是:

    挂载钩子中的两个 api 调用 - 一个用于获取带有列表的板,第二个用于获取所有卡片。 然后我循环槽列表和循环槽卡并按 id 将每张卡推入列表?

但这样看来,我的列表似乎需要一个名为 cards: [] 的空数组,仅用于按 id 进行前端卡片到列表排序,这似乎有些错误。

这是个好方法吗?或者我应该重新设计我的模型和模式并采用其他方式吗?任何帮助将不胜感激!

【问题讨论】:

这听起来很像卡片和列表属于板,对吧?我知道这看起来很奇怪,但您可以将其更新为具有 ListsCards 的单个 Board 集合。如果你只想要一个列表,你可以使用投影来限制返回的文档。对于 mongo,“属于”一般意味着您应该强烈考虑使用嵌套文档。 【参考方案1】:

您定义的架构非常好,不过只是进行了一次修改。

Board 模型中不需要有“列表”,因为它已经在列表中可用,而且如果您将其保留在 Board 中,那么每次添加新列表时,您也需要编辑 Board。

流程如下。

最初,当用户登录时,您需要向他们显示板列表。这应该很容易,因为您只需使用 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) // where board_id is the ID of the board and listId is the Id of the list

现在,让我们看看您可能同时需要来自 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'
            
        
    ])

这也将添加一系列卡片。同样,您也可以获取列表卡片。

【讨论】:

【参考方案2】:

答案有点晚,但我认为它会帮助某人。您遇到的问题可以使用聚合框架来解决。虽然另一个答案提到了一个很好的方法,但它仍然没有嵌入卡片数据。

MongoDB 文档展示了一种嵌套聚合查询的方法。 Nested Lookup

您的问题可以使用类似的方法。

Board.aggregate([
  
    $match:  _id: mongoose.Types.ObjectId(boardId) ,
  ,
  
    $lookup: 
      from: 'lists',
      let:  boardId: '$_id' ,
      pipeline: [
         $match:  $expr:  $eq: ['$boardId', '$$boardId']   ,
        
          $lookup: 
            from: 'cards',
            let:  listId: '$_id' ,
            pipeline: [ $match:  $expr:  $eq: ['$listId', '$$listId']   ],
            as: 'cards',
          ,
        ,
      ],
      as: 'lists',
    ,
  ,
]);

这会将卡片作为数组包含在每个列表中。

【讨论】:

以上是关于Mongoose/Mongodb 类似 trello 的基本方案问题,在 vue 中呈现的主要内容,如果未能解决你的问题,请参考以下文章

Mongoose / Mongodb 迁移到 MySQL

mongoose \ mongodb 按一些列表排序? [复制]

无法与 Mongoose (Mongodb) 连接

Mongoose/MongoDb 收到错误 geoNear 不是函数

Mongoose (mongodb) 批量插入、删除、更新和无操作

详解node+mongoose+mongoDb(mongoDb安装运行,在node中链接)