Search code examples
mongodbschemaschema-designdocument-storedatabase

Better ways to model this simple schema design (MongoDB)?


I have the following case: A user can add contacts (who are other users) on the website. Optionally, a user may also organize his contacts in groups. A user can have many emails, addresses and phone numbers.

I thought of the following schema design (document store/mongodb). Are there any ways to improve this? My main concern is that the profile picture is embedded inside the document. I know that this is not a good practice, but for this particular purpose (assignment), I have to embed the picture (blob/gridfs) here as well. But I'm wondering how this schema can be improved.


Solution

  • For users, I think your current schema is fine. Keeping multiple addresses, phone numbers, and email addresses in arrays is good because there shouldn't be too many of them for a particular person and it's easy to query for "who has this email address" or "give me all the phone numbers of this person". You do seem to have a redundant e-mail field though - is that a special email, like the address for the account, that's distinguished from a contact email? If so I'd give it a descriptive name for the sake of other maintainers, a name like account_email. I wouldn't keep the photo as a blob, but you said that is some other requirement so I won't critique it.

    I like the idea of doing contacts with groups using a separate contacts collection. I'd have a contacts collection with each document representing one contact

    {
        "_id" : ObjectId("..."),
        "owner_id" : ObjectId("..."), // reference to user document of contact owner
        "contact_id" : ObjectId("..."), // reference to user document of contact
        "group" : "Rivals" // group name
    }
    

    Index on { "owner_id" : 1, "contact_id" : 1 } and maybe { "owner_id" : 1, "group" : 1 } and then queries like the following will be quick:

    // get all contacts for user x
    db.contacts.find({ "owner_id" : x })
    // is user y a contact of user x?
    db.contacts.count({ "owner_id" : x, "contact_id" : y }) != 0
    // get all contacts in group "family" for user x
    db.contacts.find({ "owner_id" : x, "group" : "family" })
    

    Once you retrieve contacts, in order to retrieve human-friendly display information you will need to do a second query (application-level join) to retrieve the actual user documents of the contacts. If you want, you can denormalize some of the contact info into the contact document

    {
        "_id" : ObjectId("..."),
        "owner_id" : ObjectId("..."), // reference to user document of contact owner
        "contact_id" : ObjectId("..."), // reference to user document of contact
        "group" : "Rivals", // group name
        "contact_name" : "Franke Frankers"
    }
    

    You won't need to do a second query if you include commonly needed info, but if the contact updates his/her information you may need to update every contact document referencing them.