Avijit Sengupta
Avijit Sengupta

Reputation: 13

is it possible to check whether the user-given foreignFieldId (req.body.foreignFieldId ) exists or not before calling db.create(req.body) in MongoDB

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?

Upvotes: 1

Views: 46

Answers (1)

jQueeny
jQueeny

Reputation: 8681

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:

  1. Query the database to retrieve any Product. It doesn't matter which document is returned we just need a single document to act as the host.
  2. $set a new field on that document named test_id using the user supplied categoryId from the request.
  3. Perform a $lookup on the categories collection matching on the new test_id field.
  4. Use an $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.
  5. If there wasn't a match the 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.

Upvotes: 1

Related Questions