diff --git a/opensensor/collection_apis.py b/opensensor/collection_apis.py index beceb7f..00bc9b0 100644 --- a/opensensor/collection_apis.py +++ b/opensensor/collection_apis.py @@ -1,6 +1,6 @@ import logging from datetime import datetime, timedelta, timezone -from typing import Generic, List, Optional, Type, TypeVar, get_args, get_origin +from typing import Dict, Generic, List, Optional, Type, TypeVar, get_args, get_origin from bson import Binary from fastapi import APIRouter, Depends, HTTPException, Path, Query, Response, status @@ -187,7 +187,7 @@ def is_pydantic_model(obj): return isinstance(obj, type) and issubclass(obj, BaseModel) -def get_nested_fields(model: Type[BaseModel]): +def get_nested_fields(model: Type[BaseModel]) -> Dict[str, Type[BaseModel]]: nested_fields = {} for field_name, field in model.__fields__.items(): if is_pydantic_model(field.type_): @@ -206,7 +206,7 @@ def create_nested_pipeline(model: Type[BaseModel], prefix=""): "timestamp": "$timestamp", } - for field_name, field_type in model.__fields__.items(): + for field_name, field in model.__fields__.items(): if field_name == "timestamp": continue lookup_field = ( @@ -219,31 +219,30 @@ def create_nested_pipeline(model: Type[BaseModel], prefix=""): unit_field_name = f"{prefix}{mongo_field}_unit" pipeline["unit"] = f"${unit_field_name}" match_conditions[unit_field_name] = {"$exists": True} - else: - pipeline[field_name] = f"${full_mongo_field_name}" - match_conditions[full_mongo_field_name] = {"$exists": True} - - if field_name in nested_fields: - if get_origin(field_type.type_) is List: - nested_pipeline, nested_match = create_nested_pipeline( - nested_fields[field_name], "" # Empty prefix for list items - ) + elif field_name in nested_fields: + nested_type = nested_fields[field_name] + if get_origin(field.type_) is List: + # Handle array of nested objects + nested_pipeline, nested_match = create_nested_pipeline(nested_type, "") pipeline[field_name] = { "$map": { "input": f"${full_mongo_field_name}", "as": "item", - "in": { - k: f"$$item.{v.replace('$', '')}" for k, v in nested_pipeline.items() - }, + "in": nested_pipeline, } } match_conditions[full_mongo_field_name] = {"$exists": True, "$ne": []} else: + # Handle nested object nested_pipeline, nested_match = create_nested_pipeline( - nested_fields[field_name], f"{field_name}." + nested_type, f"{field_name}." ) pipeline[field_name] = nested_pipeline match_conditions.update({f"{field_name}.{k}": v for k, v in nested_match.items()}) + else: + # Handle simple field + pipeline[field_name] = f"${full_mongo_field_name}" + match_conditions[full_mongo_field_name] = {"$exists": True} logger.debug(f"Field: {field_name}, Full mongo field name: {full_mongo_field_name}") logger.debug(f"Resulting pipeline part: {pipeline[field_name]}")