在猫鼬中为朋友模式建模?

Posted

技术标签:

【中文标题】在猫鼬中为朋友模式建模?【英文标题】:Modelling for friends schema in mongoose? 【发布时间】:2018-10-26 01:20:30 【问题描述】:

当我在其他用户的个人资料上时,如何为我的猫鼬模式建模以获取这三个按钮?

    加好友 已请求 朋友

我的用户架构

const schema = new Mongoose.Schema(
  firstName:  type: String, default: '', trim: true ,
  lastName:  type: String, default: '', trim: true ,
,  timestamps: true )

我找不到正确的建模...并且还请在建模后建议聚合...

【问题讨论】:

这个问题的答案应该对你有帮助:***.com/questions/6183147/… 假设您有用户 A 和用户 B。当用户 A 在用户 B 的好友列表中并且用户 B 在用户 A 的列表中时,您可以定义一个好友。待定可能是当用户 A 请求成为用户 B 的朋友(因此用户 B 在用户 A 的列表中),但用户 B 没有接受(意味着用户 A 不在用户 B 的列表中)。我知道这很罗嗦,但我希望这会有所帮助。 【参考方案1】:

所以最后我做到了,我认为这可能是使用 mongodb 和 mongoose 的最佳方法

1.为用户创建模型。

    var Schema = mongoose.Schema
    const usersSchema = new Schema(
      firstName:  type: String, required: true ,
      lastName:  type: String, required: true ,
      friends: [ type: Schema.Types.ObjectId, ref: 'Friends']
    , timestamps: true)
    module.exports = mongoose.model('Users', usersSchema)

2. 为具有接受、拒绝、待处理和请求的枚举的朋友创建一个模型。

    const friendsSchema = new Schema(
      requester:  type: Schema.Types.ObjectId, ref: 'Users',
      recipient:  type: Schema.Types.ObjectId, ref: 'Users',
      status: 
        type: Number,
        enums: [
            0,    //'add friend',
            1,    //'requested',
            2,    //'pending',
            3,    //'friends'
        ]
      
    , timestamps: true)
    module.exports = mongoose.model('Friends', friendsSchema)

3. 现在 api 调用 --> 假设我们有两个用户 UserA 和 UserB... 所以当 UserA 请求 UserB 成为朋友时,我们会做两个 文档,以便用户 A 可以看到请求,用户 B 可以看到待处理 同时我们将这些文档的_id推送到用户的 朋友

    const docA = await Friend.findOneAndUpdate(
         requester: UserA, recipient: UserB ,
         $set:  status: 1 ,
         upsert: true, new: true 
    )
    const docB = await Friend.findOneAndUpdate(
         recipient: UserA, requester: UserB ,
         $set:  status: 2 ,
         upsert: true, new: true 
    )
    const updateUserA = await User.findOneAndUpdate(
         _id: UserA ,
         $push:  friends: docA._id 
    )
    const updateUserB = await User.findOneAndUpdate(
         _id: UserB ,
         $push:  friends: docB._id 
    )

4.如果UserB接受请求

    Friend.findOneAndUpdate(
         requester: UserA, recipient: UserB ,
         $set:  status: 3 
    )
    Friend.findOneAndUpdate(
         recipient: UserA requester: UserB ,
         $set:  status: 3 
    )

5.如果UserB拒绝请求

    const docA = await Friend.findOneAndRemove(
         requester: UserA, recipient: UserB 
    )
    const docB = await Friend.findOneAndRemove(
         recipient: UserA, requester: UserB 
    )
    const updateUserA = await User.findOneAndUpdate(
         _id: UserA ,
         $pull:  friends: docA._id 
    )
    const updateUserB = await User.findOneAndUpdate(
         _id: UserB ,
         $pull:  friends: docB._id 
    )

6.获取所有好友并检查登录用户是否为该用户的好友

User.aggregate([
   "$lookup": 
    "from": Friend.collection.name,
    "let":  "friends": "$friends" ,
    "pipeline": [
       "$match": 
        "recipient": mongoose.Types.ObjectId("5afaab572c4ec049aeb0bcba"),
        "$expr":  "$in": [ "$_id", "$$friends" ] 
      ,
       "$project":  "status": 1  
    ],
    "as": "friends"
  ,
   "$addFields": 
    "friendsStatus": 
      "$ifNull": [  "$min": "$friends.status" , 0 ]
    
  
])

【讨论】:

你能解释一下阻塞,解除阻塞吗? 您好,很抱歉寻求帮助,但 ObjectId.... 引用了当前登录的用户或您实际查看的配置文件? (也就是不属于您的个人资料)? 如果数组中有成千上万的朋友,这会是一个问题吗?这会导致 mongodb 出现问题吗? 不错的实现,但为什么你有一个添加朋友的枚举?我认为如果两个用户之间没有友谊,可以只推荐这个,不是吗? @OhadChaet 只是为了更清楚地说明问题。但这取决于你。:-)【参考方案2】:

这个问题有点晚了,但这是我的解决方案:

    为用户创建“自我参照”模型:
const Schema = mongoose.Schema;

// Create Schema
const UserSchema = new Schema(
   firstName:  
      type: String, 
      required: true 
   ,
   lastName:  
      type: String, 
      required: true 
   ,
   friends: [
      
         user: 
           type: Schema.Types.ObjectId,
           ref: 'users',
         ,
         status: Number,
         enums: [
           0,    //'add friend',
           1,    //'requested',
           2,    //'pending',
           3,    //'friends'
         ]
      
   ]
)

现在,如果您想查询好友,您可以使用聚合函数并匹配好友列表中的所有用户:

exports.getFriends = async (req, res) => 
  let id = req.params
  let user = await User.aggregate([
     "$match":  "_id": ObjectId(id)  ,
     "$lookup": 
      "from": User.collection.name,
      "let":  "friends": "$friends" ,
      "pipeline": [
         "$match": 
          "friends.status": 1,
        ,
         "$project":  
            "name": 1, 
            "email": 1,
            "avatar": 1
          
        
      ],
      "as": "friends"
    , 
  ])

  res.json(
    user
  )

这种方法的优点之一是您可以进行较小的查询,而不是创建一个友谊连接表,这些查询的成本可能会低一些。而且它对我来说似乎更直观。但是我对 mongo 还很陌生,所以我不太确定最佳实践是什么。

【讨论】:

以上是关于在猫鼬中为朋友模式建模?的主要内容,如果未能解决你的问题,请参考以下文章

如何在猫鼬中为具有孩子的属性分配“null”或“undefined”

如何在猫鼬节点js中为朋友创建模式

如何在猫鼬中编写键值对对象模式

是否有可能在猫鼬中有一系列替代子文档模式

关于如何在猫鼬中编写评论模式的任何想法?

关于如何在猫鼬中编写评论模式的任何想法?