Product Schema:
const productSchema = new mongoose.Schema({
name: { type: String, required: true },
price: { type: Number, required: true },
addedBy: { type: mongoose.Types.ObjectId, ref: 'User' },
categoryId: { type: mongoose.Types.ObjectId, ref: 'Category' }, //holds the id **AFTER** creation
isDeleted: { type: Boolean, default: false },
},
{
timestamps: true,
versionKey: false
});
Category Schema:
const statusEnum = ["active", "inactive"]
const categorySchema = new mongoose.Schema({
name: { type: String, required: true },
status: { type: String, enum: statusEnum, default: "active" },
isDeleted: { type: Boolean, default: false },
},
{
timestamps: true,
versionKey: false
});
I want to check, before creating a new entry in my MongoDB database, if a category in categories collection exists with the user given categoryId
.
Is it possible using an aggregation, because I don't want to import the CategoryModel
into my ProductControlller
?
It is possible to do this using an aggregation but it is really a hack/workaround when there is a clear solution - use the CategoryModel
to query first.
Nonetheless, in case you are simply testing the efficiency of different approaches, with Model.aggregate()
the logical steps might be:
Product
. It doesn't matter which document is returned we just need a single document to act as the host.$set
a new field on that document named test_id
using the user supplied categoryId
from the request.$lookup
on the categories
collection matching on the new test_id
field.$unwind
stage to unwind the array of objects that were assigned to test_id
. If there was a match, $unwind
will leave a single document - confirming that the categories
collection has a document with that _id
.test_id
field will be an empty array and given that:$unwind does not output a document if the field value is null, missing, or an empty array.
You would therefore be left with zero documents - confirming that the categories
collection doesn't have a document with that _id
.
It might look like this:
const docs = await ProductModel.aggregate([
{
$sort: { _id: 1 }
},
{
$limit: 1
},
{
$set: {
test_id: mongoose.Types.ObjectId.createFromHexString(req.body.categoryId)
}
},
{
$lookup: {
from: "categories",
localField: "test_id",
foreignField: "_id",
as: "test_id"
}
},
{
$unwind: "$test_id"
}
])
if(docs.length){
// A document does exists with that categoryId
// so free now to do a ProductModel.create()
}else{
// docs is an empty array so there was no document with categoryId
// need to return an error or whatever
}
Note: the $unwind
stage isn't quite necessary. You could simply check for if(docs.test_id.length)
but I feel leaving an empty docs
array is somewhat more conclusive semantically and this solution isn't something that I would recommend over just checking using the CategoryModel
.