0

In mongodb, I have a master table called category sample data as below:

{
    "_id" : "63d3e01f43aa4e0ee349f841",
    "subCategories" : [
        {
            "subCategoryId" : NumberLong(1), 
            "name": "Mobile phones" 
        },
        {
            "subCategoryId" : NumberLong(2), 
            "name": "XYZ Machine" 
        }
    ]
}

There is another table called product. Sample data as below:

{
    "_id" : "63d3e13b43aa4e0ee349f842",
    "productId" : NumberLong(1),
    "name" : "iphone 14",
    "category" : DBRef("category", "63d3e01f43aa4e0ee349f841")
}

While adding new product, only 1 category and 1 subcategory from that selected category can be selected. In my case, I am using @DbRef and I am struggling to find a way through which I can save only 1 subcategory within the product table. Right now it points to an entire object of the category table in which there can be x number of subcategories.

Is it possible to achieve this using @DbRef annotation without changing the database structure and without breaking the category table records in between separate category & subcategory tables ?

May be something like this:

{
    "_id" : "63d3e13b43aa4e0ee349f842",
    "productId" : NumberLong(1),
    "name" : "iphone 14",
    "category" : DBRef({"category", "63d3e01f43aa4e0ee349f841"},
                       "subCategoryId", 1)

}

Using MongoDb version 4+ with Java spring-data-mongo

jarvo69
  • 7,908
  • 2
  • 18
  • 28

1 Answers1

0

I don't think it is possible to achieve your expected behaviour without changing the schema. From official doc of DBRef,

DBRefs are a convention for representing a document, rather than a specific reference type.

So DBRef will point to a specific document, instead of certain sub-document array entry.

This leaves us 2 options:

  1. change the category collection to store document like this:
{
    "categoryId" : "63d3e01f43aa4e0ee349f841", // this is new
    "subCategoryId" : NumberLong(1), 
    "name": "Mobile phones" 
}

Unfortunately this is banned as changing schema is not allowed

  1. add another field in product schema to store the subCategory Id and use it to locate subCategory entries when $lookup
{
      "_id": "63d3e13b43aa4e0ee349f842",
      "productId": NumberLong(1),
      "name": "iphone 14",
      "category": {
        "$ref": "category",
        "$id": "63d3e01f43aa4e0ee349f841"
      },
      "subCategoryId": NumberLong(1) // this is new
    }

the aggregation:

db.product.aggregate([
  {
    $match: {
      "_id": "63d3e13b43aa4e0ee349f842"
    }
  },
  {
    "$lookup": {
      "from": "category",
      "let": {
        categoryId: "$category.$id",
        subCategoryId: "$subCategoryId"
      },
      "pipeline": [
        {
          $match: {
            $expr: {
              $eq: [
                "$$categoryId",
                "$_id"
              ]
            }
          }
        },
        {
          $unwind: "$subCategories"
        },
        {
          $match: {
            $expr: {
              $eq: [
                "$$subCategoryId",
                "$subCategories.subCategoryId"
              ]
            }
          }
        }
      ],
      "as": "subCategoryLookup"
    }
  }
])

Mongo Playground

This is also kind of banned as it needs to add one more field to the product schema. But I would still suggest this as this involves a minimal change to the schema.

ray
  • 11,310
  • 7
  • 18
  • 42