In Mongoose, there's a great and useful feature called Population, which makes it possible to dynamically connect a field to another document from another collection.
Let's say, in sales document you have costumer field. Costumer might be a person or a company. And you want to keep costumer in one field. No problem. You can create a schema like the one below.
costumer: { type: ObjectId, refPath: "costumerType" },
costumerType: { type: String, enum: ["people", "companies"] }
Then, when you need to get this sales document, you can "populate" costumer field like below.
await sales.find({}).populate("costumer")
Mongoose will bring you the costumer, whether person or company.
Very useful.
Switching to Aggregation API
If you're building much bigger app, there might be a need for complex database queries. MongoDB have a great query API called Aggregation API.
At the point that you're working with Aggregation API, you may encounter the limitation that aggregation doesn't directly support dynamic lookups — lookup ($lookup) is an operator for bringing documents from other collections in same database.
Nevertheless, nothing is impossible.
I created a trick to make dynamic lookups possible by the following method.
await sales.aggregate([
// Lookup for people and get result into "_temporaryPeople"
{ $lookup: {
from: "people",
localField: "costumer",
foreignField: "_id",
as: "_temporaryPeople",
}},
// Lookup for companies and get result into "_temporaryCompanies"
{ $lookup: {
from: "companies",
localField: "costumer",
foreignField: "_id",
as: "_temporaryCompanies",
}},
// Set "costumer" field with merge of two variables.
// This will set "costumer" the wanted document.
{ $set: {
costumer: {
$mergeObjects: [
{ $first: "$_temporaryPeople" },
{ $first: "$_temporaryCompanies" },
]
}
}},
// After we're done, we can destroy temporary fields.
{ $unset: ["_temporaryPeople", "_temporaryCompanies"] },
])
Until MongoDB adds dynamic lookup to the Aggregation API,
I think this is the easiest way to handle this issue.
Stay with MongoDB 🏄♂️
Top comments (0)