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.
- 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)
-
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'}] });
-
- 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)