简体   繁体   中英

How to filter multiple nested array object by using multi nested objects using aggregate in mongoose node js

I need to filter multiple nested array object by using multi nested objects in aggregate using mongoose nodejs. I have mention sample record data from collection and multi filter objects.

I work with one e-commerce product listing view page. In this listing page we have lot of products with different kind of features. Here I need to filter that products by using that list of product feature.

Example:

I have 3 number of mobile phones with different kind of features, like Color, RAM, Storage. These features are placed inside "productfilter" array in the below sample collection record. I could selected multiple features to filter mobile phones like, i select color: Blue, gold and RAM: 6GB, 8GB. Here second product from sample product list data, need to get as per selected filter. Because color:Blue and RAM:6GB is matched along with "IsDefault: 'true'" in second product object from sample product list data

Here need to filter records based on filter request data and along with that need to check "isDefault" to be "true"

Sample collection records

[
  {
    "_id": "5d710f9950b94f237f04407b",
    "productfilter": [
      {
        "_id": "5d8d29ae014da910c0de0799",
        "specTitle": "Color",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de079d",
            "specLabel": "Rose Gold",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-rose-gold-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de079c",
            "specLabel": "Black",
            "isDefault": "true",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-black-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de079b",
            "specLabel": "Blue",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-blue-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de079a",
            "specLabel": "Red",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-red-6gb-64gb-redmi-note-6-pro"
          }
        ]
      },
      {
        "_id": "5d8d29ae014da910c0de0796",
        "specTitle": "RAM",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de0798",
            "specLabel": "4GB",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-black-4gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de0797",
            "specLabel": "6GB",
            "isDefault": "true",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-black-6gb-64gb-redmi-note-6-pro"
          }
        ]
      },
      {
        "_id": "5d8d29ae014da910c0de0794",
        "specTitle": "Storage",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de0795",
            "specLabel": "64GB",
            "isDefault": "true",
            "specContent": ""
          }
        ]
      }
    ]
  },
  {
    "_id": "5d710fe050b94f237f04407e",
    "productfilter": [
      {
        "_id": "5d8d29ae014da910c0de07a3",
        "specTitle": "Color",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de07a7",
            "specLabel": "Rose Gold",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-rose-gold-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de07a6",
            "specLabel": "Black",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-black-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de07a5",
            "specLabel": "Blue",
            "isDefault": "true",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-blue-6gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de07a4",
            "specLabel": "Red",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-red-6gb-64gb-redmi-note-6-pro"
          }
        ]
      },
      {
        "_id": "5d8d29ae014da910c0de07a0",
        "specTitle": "RAM",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de07a2",
            "specLabel": "4GB",
            "isDefault": "false",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-blue-4gb-64gb-redmi-note-6-pro"
          },
          {
            "_id": "5d8d29ae014da910c0de07a1",
            "specLabel": "6GB",
            "isDefault": "true",
            "specContent": "mobiles-accessories-mobiles-redmi-redmi-redmi-note-6-pro-blue-6gb-64gb-redmi-note-6-pro"
          }
        ]
      },
      {
        "_id": "5d8d29ae014da910c0de079e",
        "specTitle": "Storage",
        "attributeOptions": [
          {
            "_id": "5d8d29ae014da910c0de079f",
            "specLabel": "64GB",
            "isDefault": "true",
            "specContent": ""
          }
        ]
      }
    ]
  }
]

Sample selected request data from filter option lists in product list view pages, to filter above records

{
  "filter": {
    "genericFilter": [
      {
        "specTitle": "Color",
        "specLabel": [
          "Blue",
          "Gold",
          "Rose Gold"
        ]
      },
      {
        "specTitle": "RAM",
        "specLabel": [
          "6GB",
          "8GB"
        ]
      },
      {
        "specTitle": "Storage",
        "specLabel": [
          "64GB",
          "256GB"
        ]
      }
    ]
  }
}

This can be done using Aggregation Pipeline as following

db.products.aggregate([
   {
        $unwind: "$productfilter"
   },
   {
        $unwind: "$productfilter.attributeOptions"
   },
   {
       $project: {
           "specTitle": "$productfilter.specTitle",
           "specLabel": "$productfilter.attributeOptions.specLabel",
           "isDefault": "$productfilter.attributeOptions.isDefault",
           _id:0
       }
   },
   {
       $group: {
           "_id": "$specTitle",
           "specLabel": {$addToSet: "$specLabel"}
       }
   },
   {
    $project: {
        "specTitle": "$_id",
        "specLabel": "$specLabel",
        "isDefault": "$productfilter.attributeOptions.isDefault",
        _id:0
    }
   },
])

Explanation:

  1. In first stage, the query unwinds the array productFilter ; it means dividing the document in multiple records for each value of productFilter array item
  2. In second stage it does the same for attributeOptions which was inside productFilter
  3. Project stage, keeps the relevant fields from the document and names them for later purpose
  4. Groups all documents now by specTitle and creates a new field 'specLabel'(which utilizes $addToSet to make an array from all different 'specLabel' values.). As it's a set, it does not repeat the values if it's present.
  5. Finally restructures the document as wanted. (Here I haven't included filters, genericFilter as per sample result because they are redundant but if you want, you can just edit the last stage $project to suit your needs

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM