How to get nested object data present in mongodb in C# / ASP.NET

ghz 9months ago ⋅ 176 views

How to get nested object data present in mongodb in C# / ASP.NET Core Web API

Currently I have data in this format:

{
  "_id": "6602fc150d713b8f94494338",
  "type": "Brands",
  "screenContext": {
    "title": "",
    "handle": "tapas-products",
    "media": [],
    "styles": {},
    "additionalInfo": {},
    "translations": {}
  },
  "sections": {
    "name": "Category 3x3",
    "type": "categories",
    "sectionPosition": 1,
    "styles": {
      "containerStyle": {},
      "titleNViewAllSecStyle": {},
      "tileStyle": {
        "tileSec": {
          "width": "48%",
          "marginHorizontal": "1%"
        },
        "tileImageSec": {},
        "tileImage": {
          "width": 160,
          "height": 160
        },
        "titleStyle": {}
      }
    },
    "additionalInfo": {
      "numOfColumns": 2,
      "noOfTilesOnMainView": 4,
      "showLabel": true
    },
    "subSections": [
      {
        "title": "Offers",
        "handle": "frontpage",
        "image": "products/abc.jpg",
        "navigation": {
          "tab": "AgriStoreTab",
          "screen": "AgriStoreProductsList",
          "params": {
            "nextScreenParamName": "currentScreenPayloadName"
          }
        },
        "additionalInfo": {},
        "styles": {},
        "translations": {
          "te": {
            "title": "ఆఫర్"
          },
          "hi": {
            "title": "ऑफ़र"
          },
          "ta": {
            "title": "சலுகை"
          },
          "kn": {
            "title": "ಆಫರ್"
          }
        }
      }
    ],
    "translations": {
      "te": {},
      "hi": {},
      "ta": {},
      "kn": {}
    }
  }
}

Basically when I am running this method:

public async Task<dynamic> GetAppScreensData(string type, string handle)
{            
     try
     {
          var pipeline = new[]
          {
               new BsonDocument("$match",
                   new BsonDocument
                   {
                   { "type", type },
                   { "screenContext.handle", handle }
                }),
                new BsonDocument("$unwind", "$sections"),
                new BsonDocument("$sort",
                new BsonDocument("sections.sectionPosition", 1))
          };
            
          var query = pipeline.ToJson();
          var data = await _context.AppScreens.Aggregate<BsonDocument>(pipeline).ToListAsync().ConfigureAwait(false);
          var list = data.ConvertAll(BsonTypeMapper.MapToDotNetValue);
          var json = JsonConvert.SerializeObject(list);
          var screenResponseList = JsonConvert.DeserializeObject<List<dynamic>>(json);

          if (screenResponseList.Count > 0)
          {  
              var appScreenResponse = screenResponseList.FirstOrDefault();
              return appScreenResponse;
          } 

          return new {}; 
     } 
     catch (Exception ex)
     {
          throw new ex;
     }
}

The main problem is when I am running this method, I am getting the response properly while debugging, but in Postman, the response appears like this:

{
  "_id": [],
  "type": [],
  "screenContext": [
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ]
  ],
  "sections": [
    [
      []
    ]
  ],
  "isActive": [],
  "isDeleted": [],
  "createdOn": [],
  "updatedOn": []
}
{
  "_id": [],
  "type": [],
  "screenContext": [
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ]
  ],
  "sections": [
    [
      []
    ]
  ],
  "isActive": [],
  "isDeleted": [],
  "createdOn": [],
  "updatedOn": []
}{
  "_id": [],
  "type": [],
  "screenContext": [
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ]
  ],
  "sections": [
    [
      []
    ]
  ],
  "isActive": [],
  "isDeleted": [],
  "createdOn": [],
  "updatedOn": []
}{
  "_id": [],
  "type": [],
  "screenContext": [
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ],
    [
      []
    ]
  ],
  "sections": [
    [
      []
    ]
  ],
  "isActive": [],
  "isDeleted": [],
  "createdOn": [],
  "updatedOn": []
}

What can be the reason for this? How to resolve it?

I tried to keep return type as IEnumerable, BsonDocument, dynamic but nothing works.

The mongo data can have further nesting of objects so that Json will be dynamic and I cannot keep any fixed model for this.

Answers

The issue you're encountering appears to be related to how the data is being deserialized and returned from your GetAppScreensData method. When you're debugging the method, you're seeing the data properly, but when you make the request through Postman, the response is not as expected.

The problem seems to arise from the way you're converting the MongoDB documents to JSON and then deserializing them back to dynamic objects. Since your data structure is dynamic and can have nested objects, it requires special handling to ensure proper serialization and deserialization.

Here's a revised version of your method that uses BsonDocument throughout and directly returns it without converting to JSON:

public async Task<BsonDocument> GetAppScreensData(string type, string handle)
{
    try
    {
        var pipeline = new[]
        {
            new BsonDocument("$match",
                new BsonDocument
                {
                    { "type", type },
                    { "screenContext.handle", handle }
                }),
            new BsonDocument("$unwind", "$sections"),
            new BsonDocument("$sort",
                new BsonDocument("sections.sectionPosition", 1))
        };

        var data = await _context.AppScreens.Aggregate<BsonDocument>(pipeline).ToListAsync().ConfigureAwait(false);

        if (data.Count > 0)
        {
            return data.First();
        }

        return new BsonDocument();
    }
    catch (Exception ex)
    {
        throw ex;
    }
}

By returning BsonDocument directly, you ensure that the dynamic structure of your data is preserved without any loss of information during serialization/deserialization. This should help resolve the issue you're facing with the response in Postman.

Make sure to update the calling code to handle BsonDocument instead of dynamic if necessary. Additionally, consider adding error handling and logging to improve the robustness of your method.