Skip to content

Instantly share code, notes, and snippets.

@luisjunco
Last active September 29, 2023 20:37
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.

Relationship types

  • One-to-One Relationships (1:1)
    • Ex. Product + specs(size, weight,...)
  • One-to-Many Relationships (1:many)
    • Ex. Product + Seller
  • Many-to-Many Relationships (many:many)
    • Ex. Product + Seller (in case a product can be sold by multiple sellers)

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: faster queries
      • problem: single source of truth, easier to corrupt 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