How do I model my mongoose schema to get these three buttons when I am on the other users profile?
My users schema
const schema = new Mongoose.Schema({
firstName: { type: String, default: '', trim: true },
lastName: { type: String, default: '', trim: true },
}, { timestamps: true })
I could not find the correct modelling for this... And also please suggest the aggregation after modelling...
So Finally I made it and I think it is probably the best way to do it with mongodb and mongoose
1. Create a model for users.
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. Create a model for friends having enums for accepted, rejected, pending and requested.
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. Now api calls --> Lets say we have two users UserA and UserB... So when UserA requestes UserB to be a friends at that time we make two documents so that UserA can see requested and UserB can see pending and at the same time we push the _id of these documents in user's friends
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. If UserB acceptes the request
Friend.findOneAndUpdate(
{ requester: UserA, recipient: UserB },
{ $set: { status: 3 }}
)
Friend.findOneAndUpdate(
{ recipient: UserA requester: UserB },
{ $set: { status: 3 }}
)
5. If UserB rejectes the request
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. Get all friends and check whether the logged in user is friend of that user or not
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 ]
}
}}
])
A little late for this question, but here's my solution:
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'
]
}
]
})
Now if you want to query for friends you can use an aggregate function and match all users that are in the friends list:
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
})
}
One of the pro's to this approach rather than creating a Friendship join table is that you can make smaller queries that can be a bit less expensive to make. Also it seemed more intuitive to me. However I'm pretty new to mongo so I'm not really sure what the best practices are.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With