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

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

  1. 加好友
  2. 已请求
  3. 朋友

我的用户架构

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

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

【问题讨论】:

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

标签: node.js mongodb mongoose mongodb-query aggregation-framework


【解决方案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】:

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

  1. 为用户创建“自我参照”模型:
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 还很陌生,所以我不太确定最佳实践是什么。

【讨论】:

    猜你喜欢
    • 2012-04-22
    • 1970-01-01
    • 1970-01-01
    • 2012-02-02
    • 2016-08-05
    • 2014-08-31
    • 1970-01-01
    • 2014-07-27
    • 2021-04-01
    相关资源
    最近更新 更多