Skip to content

Instantly share code, notes, and snippets.

@luisjunco
Last active May 23, 2024 08:53
Show Gist options
  • Save luisjunco/a507e9f15acb32620cf8a33fff0904b1 to your computer and use it in GitHub Desktop.
Save luisjunco/a507e9f15acb32620cf8a33fff0904b1 to your computer and use it in GitHub Desktop.
Cheatsheet Data Models

Embedded documents vs. References

There's 2 ways of storing complex data and relationships in MongoDB/Mongoose.

  • Embedded documents

    const authorSchema = new Schema({
        //...
    });
    
    const bookSchema = new Schema({
        title: String,
        author: authorSchema, // Single embedded document
        authors: [authorSchema], // Array of embedded documents
    });
  • References (aka. "Normalized data model")

    const bookSchema = new mongoose.Schema({
        title: String,
        author: {type: mongoose.Schema.Types.ObjectId, ref: 'Author'}, //single reference
        authors: [ {type: mongoose.Schema.Types.ObjectId, ref: 'Author'} ] //multiple
    });

Note:

  • for each of those options, we can store single/multiple.
  • in Mongoose, we use [ ] to store multiple.

Types of relationships

One-to-One Relationships (1:1)

  • example: in our application, an author can only write one book.
    • 1 book → 1 author
    • 1 author → 1 book

One-to-Many Relationships (1:many)

  • example: in our application, an author can write multiple books
    • 1 book → 1 author
    • 1 author → many books

Many-to-Many Relationships (many:many)

  • example: in our application, a book can be written by multiple authors
    • 1 book → many authors
    • 1 author → many books

Recommendations

  • 1:1 relationships --> use Embedded Documents

    const addressSchema = new Schema({
        city: String,
        postCode: String
    });
    
    const companySchema = new Schema({
        name: String,
        numberOfEmployees: Number,
        address: addressSchema
    });
  • 1:many relationships --> option A, use Embedded Documents if possible (not duplicating data & limited data size).

    • For example, if a company can have multiple locations but we assume that we will have only one company in each location (so we would not be repeating information)

      const addressSchema = new Schema({
          city: String,
          postCode: String
      });
      
      const companySchema = new Schema({
          name: String,
          numberOfEmployees: Number,
          address: [addressSchema]
      });
  • 1:many relationships --> option B, Reference

    • For example, if a company can have only ONE location... but we assume that we may have multiple companies in the same location (so we could be repeating information)

      const companySchema = new Schema({
          name: String,
          numberOfEmployees: Number,
          address: {type: mongoose.Schema.Types.ObjectId, ref: 'Address'}
      });
  • many:many relationships --> use Reference

    • For example, if a company can have multiple locations... and we assume that we may have multiple companies in the same location.

      const companySchema = new Schema({
          name: String,
          numberOfEmployees: Number,
          address: [{type: mongoose.Schema.Types.ObjectId, ref: 'Address'}]
      });

Examples (e-commerce app):

  • Product + specs(size, weight,...) (1:1)
  • Product + reviews (1:many with embedded documents)
  • Product + Seller (1:many with references)
    • opt1: store ref. in the seller (need to keep an array)
    • opt2: store ref. in the product (easier)
    • opt3: store ref. in both models
      • advantage: reading is easier / faster
      • problem: create, update and delete is usually more complex. Also, we don't have a single source of truth (so we may end up with inconsistencies in our DB)
  • (bonus) In case each product can have multiple sellers (many:many with references)
    • store [ref.] in the seller (easier to get list of products from seller)
    • store [ref.] in the product (easier to get list of sellers of a product)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment