Hướng dẫn mongodb friendship schema

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 ]
    }
  }}
])

I am going back and forth on the best way to design the Schema between friends and groups, these are fields in a document for each user, so as they add friends and put them into groups they will all live under each user.

Right now I have friends and groups seperated, however do I need to do that? Can I just have friends and then add a group attribute to the friends array of objects?

friends: [ {email: "", username: "bob", group: ["friends", "family","guys"]]

this is what I have now.

 groups: [
    {
        groupName: {type:String, required: true, unique: true},
        members:
            [{
                type: mongoose.Schema.Types.ObjectId,
                ref: "User",
                username: String,
                email: String
            }]
}],
friends: [
    {
        type: mongoose.Schema.Types.ObjectId,
        ref: "User",
        username: String,
        email: {type:String, required: true, index: true}
}],

I would like to display how many people are in each group and what members, I would like to send out notifications and emails by group as well as by individual friends. Im just looking for a second opinion here.

Nội dung bài viết

Video học lập trình mỗi ngày

Một trong những người mới học về database, bất kể mongodb, mysql hay oracle thì việc xây dựng những lược đồ (schema) là một điều quan trọng. Nếu ngay từ đầu bạn làm tốt thì sau này mọi chuyển trở nên đơn giản cho những người đến sau hoặc hệ thống được nâng cấp.

Schema trong mongodb và lưu ý quan trọng

Bạn sẽ đọc ở bất cứ đâu về mongodb và bạn sẽ biết có bao nhiêu cách MongoDB schema design qua những documents đó nhưng, bạn lưu ý cho tôi một điều duy nhất. Đó là bạn phải phân biệt được ứng dụng của bạn có tỷ lệ đọc (read ratio) và tỷ lệ write (write ratio) như thế nào?

Nếu bạn chưa hiểu thì để tôi nói thế này cho nhanh hiểu. Ví dụ: Bạn triển khai một trang web về thông báo các văn bản của một tổ chức, thì tôi dám chắc rằng read ratio là cao hơn write. Vì vậy bạn phải nghiên cứu lược đồ và mối quan hệ trong database của mình sẽ được thiết kế như thế nào, để việc đọc phải nhanh mà không cần có quá nhiều ràng buộc.

Ngược lại nếu bạn tham gia một ứng dụng về track log trong một hệ thống bảo trì nào đó thì có lẽ là tỷ lệ ghi là nhiều, và mỗi tháng chỉ đọc 1 lần về báo cáo. Đó là những ví dụ có thể hiểu dễ nhất mà tôi có thể giải thích cho bạn.

Lưu ý thứ hai là những gì tôi viết trong ngoặc (...) xuyên suốt bài viết là những điều mà các bạn phải nên tìm hiểu. Đó là (MMAP) và (WiredTiger).

Schema design trong MongoDB nên học

Tôi biết mọi người rất nóng vội trang bị cho mình những kiến thức nâng cao về database, nhưng trước tiên theo tôi thì các bạn phải xem lại các khái niệm cơ bản về lược đồ. Trong bài viết đầu tiên của Series MongoDB schema design thì tôi và bạn sẽ khám phá các mối quan hệ trong database từ truyền thống (mysql, oracle) cho đến phi truyền thống NoSQL và đại diện sẽ là Mongodb.

Chúng ta sẽ bắt đầu với việc xem xét mối quan hệ One-To-One (1: 1) sau đó chuyển sang One-To-Many(1: N) và cuối cùng là Many-To-Many (N: M).

Mối quan hệ 1 - 1 trong Database (One-To-One)

Để hình dung câu chuyện cho dễ thì tôi lấy một ví dụ và đi xuyên suốt trong Series lần này đó là văn hóa gia đình của quốc gia Việt Nam. Sự chung thủy, ngoại tình và ông ăn chả và bà ăn nem. Chú ý: không nên ngoại tình và ăn nem và chả dưới hình bất cứ hình thức nào.... Nhớ lấy.

Mối quan hệ 1 : 1 hay còn gọi là One-To-One là được biểu diễn qua 2 entities. Trong ví dụ này thì đó là NamNữ.

Mối quan hệ 1: 1 có thể được mô hình hóa theo hai cách bằng cách sử dụng MongoDB. Đầu tiên là nhúng (embed) mối quan hệ dưới dạng tài liệu, thứ hai là dưới dạng liên kết (Linking) đến document trong mỗi collection riêng biệt. Hãy xem xét cả hai cách lập mô hình mối quan hệ 1-1 bằng hai documents sau:

Ví dụ về document MALES

{
    name: 'Nguyen Van A',
    age: 30
}

Ví dụ về document MALES

{
    name: 'Trần Thị B',
    age: 28
}

Vì hai người yêu nhau chung thủy nên cưới nhau do đó luật pháp Việt Nam chỉ cho phép 1 chồng và 1 vợ. Vì vậy mồ hình này gọi là 1 - 1. Và nếu áp dụng trong kiến trúc model thì chúng ta có 2 cách và hay xem xét từng cách 1 để chúng ta sẽ có đánh giá ưu và nhược điểm của mỗi cách.

Cách 1: Embed

Cách đơn giản nhất khi đưa họ về một nhà (hộ khẩu) chính là nhúng lồng vào nhau. Ví dụ Anh A và chồng của chị B thì như sau:

{
    name: 'Nguyen Van A',
    age: 30,
    wife: {
        name: 'Tran Thi B',
        age: 28
    }
}

Điểm mạnh của cách này là khi chúng ta query để xem data thì chỉ thực hiện một lần với lệnh findOne. Có lẽ là phương pháp này ok, nhưng hãy xem cách thứ 2.

Cách 2: Linking

Cách tiếp cận thứ hai là liên kết người chồng và người vợ bằng cách sử dụng một foreign key. Ví dụ:

{
    _id: 1,
    name: 'Nguyen Van A',
    age: 30
}

Thì người vợ sẽ là:

{
    _id: 2,
    husbandId: 1,
    name: 'Tran Thi B',
    age: 28
}

Ta dễ dàng thấy cách 2 giống như các mô hình quan hệ kiểu truyền thống. Và muốn tìm thì chúng ta phải query hai lần, find chồng sau đó tìm vợ thông qua một husbandId.

Vì vậy qua 2 cách tôi nghĩ nếu xác định đó là 1-1 thì chúng ta nên sử dụng cách đầu chính là embed trong Mongodb.

Bài sau chúng ta sẽ phân tích về mô hình thứ hai đó chính là One-To-Many (1:N). Nhớ vào kênh youtube để ủng hộ và nghe giọng tuyệt vời của mình nhé. Tổng chào!