Search code examples
node.jsmongodbmongodb-queryaggregation-frameworknosql-aggregation

How to access the data in multi nested document in mongodb?


I need to access the data from the multi nested subdocument by omitting some fields of the nested document. The schema is shown below and the output expected is also shown below. Since projections cannot be used at the nested level so how can I do that?

given below is the database schema which is having nested entries as shown.

[
  {
    "_id": {
      "$oid": "60e519db4e0f140328adc7c7"
    },
    "trans": {
      "en": {
        "name": "Graphics And Design",
        "description": "Graphics And Design"
      },
      
    },
    "counts": {
      "$numberInt": "0"
    },
    "is_visible": true,
    "slug": "graphics-and-design",
    "image": "",
    "created_at": {
      "$numberDouble": "1625627099104.0"
    },
    "subcategories": [
      {
        "trans": {
          "en": {
            "name": "LOGO DESIGN",
            "description": "LOGO DESIGN"
          },
          "fr": {
            "name": "LOGO DESIGN",
            "description": "LOGO DESIGN"
          }
        },
        "counts": {
          "$numberInt": "0"
        },
        "slug": "logo-design",
        "is_visible": true,
        "image": "",
        "_id": {
          "$oid": "60e51a116678530e84ee2e61"
        },
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "service_type": [
          {
            "trans": {
              "en": {
                "name": "3D logo",
                "description": "3D logo design"
              },
              "fr": {
                "name": "3D logo",
                "description": "3D logo design"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e60"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          }
        ]
      },
      {
        "trans": {
          "en": {
            "name": "BRAND STYLE GUIDES",
            "description": "BRAND STYLE GUIDES"
          },
          "fr": {
            "name": "BRAND STYLE GUIDES",
            "description": "BRAND STYLE GUIDES"
          }
        },
        "counts": {
          "$numberInt": "0"
        },
        "slug": "brand-style-guides",
        "is_visible": true,
        "image": "",
        "_id": {
          "$oid": "60e51a116678530e84ee2e63"
        },
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "service_type": [
          {
            "trans": {
              "en": {
                "name": "Brand style 1",
                "description": "Brand style 1"
              },
              "fr": {
                "name": "Brand style 1",
                "description": "Brand style 1"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e62"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          },
          {
            "trans": {
              "en": {
                "name": "Brand style 2",
                "description": "Brand style 2"
              },
              "fr": {
                "name": "Brand style 2",
                "description": "Brand style 2"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e62"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          }
        ]
      }
    ],
    "updated_at": {
      "$date": {
        "$numberLong": "1625627153547"
      }
    }
  },
//this is the another category
  {
    "_id": {
      "$oid": "60e519db4e0f140328adc7c8"
    },
    "trans": {
      "en": {
        "name": "Graphics And Design2",
        "description": "Graphics And Design2"
      },
      "fr": {
        "name": "Graphics And Design2",
        "description": "Graphics And Design2"
      }
    },
    "counts": {
      "$numberInt": "0"
    },
    "is_visible": true,
    "slug": "graphics-and-design2",
    "image": "",
    "created_at": {
      "$numberDouble": "1625627099104.0"
    },
    "subcategories": [
      {
        "trans": {
          "en": {
            "name": "LOGO DESIGN2",
            "description": "LOGO DESIGN2"
          },
          "fr": {
            "name": "LOGO DESIGN2",
            "description": "LOGO DESIGN2"
          }
        },
        "counts": {
          "$numberInt": "0"
        },
        "slug": "logo-design2",
        "is_visible": true,
        "image": "",
        "_id": {
          "$oid": "60e51a116678530e84ee2e61"
        },
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "service_type": [
          {
            "trans": {
              "en": {
                "name": "3D logo2",
                "description": "3D logo design2"
              },
              "fr": {
                "name": "3D logo2",
                "description": "3D logo design2"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e60"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          }
        ]
      },
      {
        "trans": {
          "en": {
            "name": "BRAND STYLE GUIDES2",
            "description": "BRAND STYLE GUIDES2"
          },
          "fr": {
            "name": "BRAND STYLE GUIDES2",
            "description": "BRAND STYLE GUIDES2"
          }
        },
        "counts": {
          "$numberInt": "0"
        },
        "slug": "brand-style-guides2",
        "is_visible": true,
        "image": "",
        "_id": {
          "$oid": "60e51a116678530e84ee2e63"
        },
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "service_type": [
          {
            "trans": {
              "en": {
                "name": "Brand style 12",
                "description": "Brand style 12"
              },
              "fr": {
                "name": "Brand style 12",
                "description": "Brand style 12"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e62"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          },
          {
            "trans": {
              "en": {
                "name": "Brand style 22",
                "description": "Brand style 22"
              },
              "fr": {
                "name": "Brand style 22",
                "description": "Brand style 22"
              }
            },
            "counts": {
              "$numberInt": "0"
            },
            "is_visible": true,
            "_id": {
              "$oid": "60e51a116678530e84ee2e62"
            },
            "image": "",
            "slug": "null",
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": []
          }
        ]
      }
    ],
    "updated_at": {
      "$date": {
        "$numberLong": "1625627153547"
      }
    }
  }
]

Code I have tried so far:

 const client = await Database.connect();
        const lang = "en";
        const r = await client
          .collection("categories")
          .aggregate([
            {
              $addFields: {
                categories: {
                  $map: {
                    input: "$categories",
                    as: "c",
                    in: {
                      $mergeObjects: [
                        "$$this",
                        {
                          trans: `$$c.trans.${lang}`,

                          subcategories: {
                            $map: {
                              input: "$subcategories",
                              as: "s",
                              in: {
                                $mergeObjects: [
                                  "$$this",
                                  {
                                    trans: `$$s.trans.${lang}`,
                                    service_type: {
                                      $map: {
                                        input: "$$s.service_type",
                                        as: "d",
                                        in: {
                                          $mergeObjects: [
                                            "$$this",
                                            { trans: `$$d.trans.${lang}` },
                                          ],
                                        },
                                      },
                                    },
                                  },
                                ],
                              },
                            },
                          },
                        },
                      ],
                    },
                  },
                },
              },
            },
          ])
          .toArray();
        console.log(r);

Response of console.log(r):

:: FieldPath field names may not start with '$'

Expected output:

[
  {
    "_id": ObjectId("60e519db4e0f140328adc7c7"),
    "counts": 0,
    "created_at": {
      "$numberDouble": "1625627099104.0"
    },
    "image": "",
    "is_visible": true,
    "slug": "graphics-and-design",
    "subcategories": [
      {
        "_id": ObjectId("60e51a116678530e84ee2e61"),
        "counts": 0,
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "image": "",
        "is_visible": true,
        "service_type": [
          {
            "_id": ObjectId("60e51a116678530e84ee2e60"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "service_type1",
            "trans": {
              "description": "service_type1",
              "name": "service_type1"
            }
          }
        ],
        "slug": "logo-design",
        "trans": {
          "description": "LOGO DESIGN",
          "name": "LOGO DESIGN"
        }
      },
      {
        "_id": ObjectId("60e51a116678530e84ee2e63"),
        "counts": 0,
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "image": "",
        "is_visible": true,
        "service_type": [
          {
            "_id": ObjectId("60e51a116678530e84ee2e62"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "null",
            "trans": {
              "description": "ServiceType1_BRAND STYLE GUIDES",
              "name": "ServiceType1_BRAND STYLE GUIDES"
            }
          },
          {
            "_id": ObjectId("60e51a116678530e84ee2e62"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "null",
            "trans": {
              "description": "ServiceType2_BRAND STYLE GUIDES",
              "name": "ServiceType2_BRAND STYLE GUIDES"
            }
          }
        ],
        "slug": "brand-style-guides",
        "trans": {
          "description": "BRAND STYLE GUIDES",
          "name": "BRAND STYLE GUIDES"
        }
      }
    ],
    "trans": {
      
        "description": "Graphics And Design",
        "name": "Graphics And Design"
     
    },
    "updated_at": ISODate("2021-07-07T03:05:53.547Z")
  },
  {
    "_id": ObjectId("60e519db4e0f140328adc7c8"),
    "counts": 0,
    "created_at": {
      "$numberDouble": "1625627099104.0"
    },
    "image": "",
    "is_visible": true,
    "slug": "graphics-and-design2",
    "subcategories": [
      {
        "_id": ObjectId("60e51a116678530e84ee2e61"),
        "counts": 0,
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "image": "",
        "is_visible": true,
        "service_type": [
          {
            "_id": ObjectId("60e51a116678530e84ee2e60"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "null",
            "trans": {
              "description": "ServiceType1_LOGO DESIGN2",
              "name": "ServiceType1_LOGO DESIGN2"
            }
          }
        ],
        "slug": "logo-design2",
        "trans": {
          "description": "LOGO DESIGN2",
          "name": "LOGO DESIGN2"
        }
      },
      {
        "_id": ObjectId("60e51a116678530e84ee2e63"),
        "counts": 0,
        "created_at": {
          "$numberDouble": "1625627153535.0"
        },
        "image": "",
        "is_visible": true,
        "service_type": [
          {
            "_id": ObjectId("60e51a116678530e84ee2e62"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "null",
            "trans": {
              "description": "ServiceType1_BRAND STYLE GUIDES2",
              "name": "ServiceType1_BRAND STYLE GUIDES2"
            }
          },
          {
            "_id": ObjectId("60e51a116678530e84ee2e62"),
            "counts": 0,
            "created_at": {
              "$numberDouble": "1625627153535.0"
            },
            "gig_meta_data": [],
            "image": "",
            "is_visible": true,
            "slug": "null",
            "trans": {
              "description": "ServiceType2_BRAND STYLE GUIDES2",
              "name": "ServiceType2_BRAND STYLE GUIDES2"
            }
          }
        ],
        "slug": "brand-style-guides2",
        "trans": {
          "description": "BRAND STYLE GUIDES2",
          "name": "BRAND STYLE GUIDES2"
        }
      }
    ],
    "trans": {
        "description": "Graphics And Design2",
        "name": "Graphics And Design2"
    },
    "updated_at": ISODate("2021-07-07T03:05:53.547Z")
  }
]

please help in resolving this issue with any good and valid approaches.


Solution

  • I am not getting your try, you can try the below approach,

    • $map to iterate loop of subcategories array
    • $map to iterate loop of service_type array
    • select trans object by input language
    • $mergeObjects to merge updated trans field and current object of service_type array
    • $mergeObjects to merge updated trans and service_type array with current object of subcategories array
    var lang = "en";
    const r = await client.collection("categories").aggregate([
      {
        $addFields: {
          trans: "$trans.en",
          subcategories: {
            $map: {
              input: "$subcategories",
              as: "s",
              in: {
                $mergeObjects: [
                  "$$s",
                  {
                    trans: `$$s.trans.${lang}`,
                    service_type: {
                      $map: {
                        input: "$$s.service_type",
                        in: {
                          $mergeObjects: ["$$this", { trans: `$$this.trans.${lang}` }]
                        }
                      }
                    }
                  }
                ]
              }
            }
          }
        }
      }
    ]).toArray();
    console.log(r);
    

    Playground