22from pathlib import Path
33from typing import Any , Dict , List
44
5+ from bson import ObjectId
56from pymongo import MongoClient
67
78from common import ROOT , coerce_bool , coerce_float , coerce_int , load_config , parse_args , parse_json_field , write_csv , write_json
89
910
11+ def convert_objectid_to_str (obj : Any ) -> Any :
12+ """Recursively convert MongoDB ObjectId objects to strings."""
13+ if isinstance (obj , ObjectId ):
14+ return str (obj )
15+ elif isinstance (obj , dict ):
16+ return {key : convert_objectid_to_str (value ) for key , value in obj .items ()}
17+ elif isinstance (obj , list ):
18+ return [convert_objectid_to_str (item ) for item in obj ]
19+ else :
20+ return obj
21+
22+
1023def flatten_match_row (entry : Dict [str , Any ]) -> Dict [str , Any ]:
1124 metadata = entry .get ('metadata' ) or {}
1225 return {
@@ -16,26 +29,26 @@ def flatten_match_row(entry: Dict[str, Any]) -> Dict[str, Any]:
1629 'robotPosition' : metadata .get ('robotPosition' , '' ),
1730 'robotAbsent' : coerce_bool (entry .get ('robotAbsent' , False )),
1831 'autoStartingPosition' : entry .get ('autoStartingPosition' ),
19- 'autoPathJson' : json .dumps (entry .get ('autoPath' ) or {}, separators = (',' , ':' )),
20- 'shootTimeBySegmentJson' : json .dumps (entry .get ('shootTimeBySegment' ) or {}, separators = (',' , ':' )),
21- 'passTimeBySegmentJson' : json .dumps (entry .get ('passTimeBySegment' ) or {}, separators = (',' , ':' )),
22- 'actionTimelineJson' : json .dumps (entry .get ('actionTimeline' ) or {}, separators = (',' , ':' )),
32+ 'autoPathJson' : json .dumps (convert_objectid_to_str ( entry .get ('autoPath' ) or {}) , separators = (',' , ':' )),
33+ 'shootTimeBySegmentJson' : json .dumps (convert_objectid_to_str ( entry .get ('shootTimeBySegment' ) or {}) , separators = (',' , ':' )),
34+ 'passTimeBySegmentJson' : json .dumps (convert_objectid_to_str ( entry .get ('passTimeBySegment' ) or {}) , separators = (',' , ':' )),
35+ 'actionTimelineJson' : json .dumps (convert_objectid_to_str ( entry .get ('actionTimeline' ) or {}) , separators = (',' , ':' )),
2336 'ballsPerSecondUsed' : coerce_float (entry .get ('ballsPerSecondUsed' , 0 )),
2437 'autoFuelScored' : coerce_float (entry .get ('autoFuelScored' , 0 )),
25- 'teleFuelBySegmentJson' : json .dumps (entry .get ('teleFuelBySegment' ) or {}, separators = (',' , ':' )),
38+ 'teleFuelBySegmentJson' : json .dumps (convert_objectid_to_str ( entry .get ('teleFuelBySegment' ) or {}) , separators = (',' , ':' )),
2639 'teleTower' : entry .get ('teleTower' , 'None' ),
2740 'breakdown' : entry .get ('breakdown' , 'None' ),
2841 'driverQuality' : entry .get ('driverQuality' , 'ok' ),
2942 'defenseProvided' : entry .get ('defenseProvided' , 'None' ),
3043 'defenseReceived' : coerce_bool (entry .get ('defenseReceived' , False )),
31- 'foulsJson' : json .dumps (entry .get ('fouls' ) or {}, separators = (',' , ':' )),
32- 'breaksJson' : json .dumps (entry .get ('breaks' ) or {}, separators = (',' , ':' )),
44+ 'foulsJson' : json .dumps (convert_objectid_to_str ( entry .get ('fouls' ) or {}) , separators = (',' , ':' )),
45+ 'breaksJson' : json .dumps (convert_objectid_to_str ( entry .get ('breaks' ) or {}) , separators = (',' , ':' )),
3346 'freeText' : entry .get ('freeText' , '' ),
3447 }
3548
3649
3750def flatten_pit_row (entry : Dict [str , Any ]) -> Dict [str , Any ]:
38- intake = parse_json_field (entry .get ('intakeSources' ), {})
51+ intake = parse_json_field (convert_objectid_to_str ( entry .get ('intakeSources' ) ), {})
3952 if not isinstance (intake , dict ):
4053 intake = {}
4154
0 commit comments