From dbed1805066d4fbedae6081f6cf54ef44c18aa47 Mon Sep 17 00:00:00 2001 From: shreddd Date: Wed, 11 Jun 2025 22:42:34 -0700 Subject: [PATCH 1/8] support docker based ingest --- docker-compose.yml | 15 +++++++++++++++ mongodb/README.md | 15 +++++++++++++++ src/server.py | 17 +++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/docker-compose.yml b/docker-compose.yml index 13dda78..4df879e 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -34,6 +34,21 @@ services: volumes: - mongo_data:/data/db + ingest: + # Use the same container image as the app service for consistency + build: { context: ".", dockerfile: Dockerfile, target: development } + # This service should not start automatically - only run on demand + profiles: ["tools"] + environment: + # Set the MongoDB connection string to connect to the mongo service + MONGO_URI: "mongodb://admin:root@mongo:27017" + volumes: + # Mount the root directory to access the ingest script and data files + - ".:/app" + depends_on: + - mongo + # Run ingest with data dir mounted to /data + command: ["uv", "run", "python", "/app/mongodb/ingest_data.py", "--mongo-uri", "mongodb://admin:root@mongo:27017", "--input", "/data"] volumes: # Define a named volume that will contain MongoDB data. diff --git a/mongodb/README.md b/mongodb/README.md index b043a73..7aae70e 100644 --- a/mongodb/README.md +++ b/mongodb/README.md @@ -12,6 +12,8 @@ This tool ingests BERtron-formatted data into MongoDB. ## Usage +### Local Python Usage + Run the ingest script with your data file: ```bash @@ -25,6 +27,19 @@ python ingest_data.py --input your_data_file.json - `--schema-path`: Path or URL to the schema JSON file (default: `bertron_schema.json` in the current directory) - `--input`: Path to input JSON file or directory containing JSON files (required) +### Using Docker Compose + +We have a ingester script in docker-compose that lets you run an ingest against a data directory + +```bash +# Start MongoDB and FASTAPI service +docker compose up + +# Pass in an ingest dir and run ingester +docker compose run --rm --volume /path/to/data:/data ingest +``` + + ## Data Format The input data should conform to the `bertron_schema.json` schema. It can be either: diff --git a/src/server.py b/src/server.py index 554984a..c790d99 100644 --- a/src/server.py +++ b/src/server.py @@ -30,6 +30,23 @@ def get_database_names(): db_names = mongo_client.list_database_names() return {"database_names": db_names} +@app.get("/database/{db_name}/{collection_name}") +def get_collection_data(db_name: str, collection_name: str): + r"""Get all documents from a specified collection in a specified database.""" + db = mongo_client[db_name] + collection = db[collection_name] + # Fetch all documents from the collection + if collection is None: + return {"error": "Collection not found"} + + documents = list(collection.find({})) + + # Remove the MongoDB '_id' field from each document for JSON serialization + for doc in documents: + doc.pop('_id', None) + + return {"documents": documents} + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) From b090ddc027bb0a0a43c5c1250da15a27f8a2481f Mon Sep 17 00:00:00 2001 From: shreddd Date: Wed, 11 Jun 2025 22:45:48 -0700 Subject: [PATCH 2/8] reformat w/ ruff --- src/server.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/server.py b/src/server.py index c790d99..25aa961 100644 --- a/src/server.py +++ b/src/server.py @@ -30,6 +30,7 @@ def get_database_names(): db_names = mongo_client.list_database_names() return {"database_names": db_names} + @app.get("/database/{db_name}/{collection_name}") def get_collection_data(db_name: str, collection_name: str): r"""Get all documents from a specified collection in a specified database.""" @@ -38,12 +39,12 @@ def get_collection_data(db_name: str, collection_name: str): # Fetch all documents from the collection if collection is None: return {"error": "Collection not found"} - + documents = list(collection.find({})) # Remove the MongoDB '_id' field from each document for JSON serialization for doc in documents: - doc.pop('_id', None) + doc.pop("_id", None) return {"documents": documents} From cdb0c57ca65a7ce59b1c034d12e59a823ceb76fb Mon Sep 17 00:00:00 2001 From: Shreyas Cholia Date: Wed, 11 Jun 2025 22:49:40 -0700 Subject: [PATCH 3/8] Update src/server.py Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- src/server.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/server.py b/src/server.py index 25aa961..34d4c74 100644 --- a/src/server.py +++ b/src/server.py @@ -35,11 +35,11 @@ def get_database_names(): def get_collection_data(db_name: str, collection_name: str): r"""Get all documents from a specified collection in a specified database.""" db = mongo_client[db_name] - collection = db[collection_name] - # Fetch all documents from the collection - if collection is None: + # Check if the collection exists in the database + if collection_name not in db.list_collection_names(): return {"error": "Collection not found"} + collection = db[collection_name] documents = list(collection.find({})) # Remove the MongoDB '_id' field from each document for JSON serialization From a7812427c1a710a81de1e720f123f55909d76d78 Mon Sep 17 00:00:00 2001 From: Shreyas Cholia Date: Thu, 12 Jun 2025 10:13:58 -0700 Subject: [PATCH 4/8] Update mongodb/README.md Co-authored-by: eecavanna <134325062+eecavanna@users.noreply.github.com> --- mongodb/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mongodb/README.md b/mongodb/README.md index 7aae70e..78ae358 100644 --- a/mongodb/README.md +++ b/mongodb/README.md @@ -35,7 +35,7 @@ We have a ingester script in docker-compose that lets you run an ingest against # Start MongoDB and FASTAPI service docker compose up -# Pass in an ingest dir and run ingester +# Mount the directory whose contents you want to ingest, and run the ingester docker compose run --rm --volume /path/to/data:/data ingest ``` From 16527d1d2905539a1a8a1b52bd344aeaea7692a2 Mon Sep 17 00:00:00 2001 From: shreddd Date: Thu, 12 Jun 2025 10:21:44 -0700 Subject: [PATCH 5/8] raise 404 --- src/server.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/server.py b/src/server.py index 34d4c74..63e88aa 100644 --- a/src/server.py +++ b/src/server.py @@ -1,4 +1,4 @@ -from fastapi import FastAPI +from fastapi import FastAPI, HTTPException import uvicorn from fastapi.responses import RedirectResponse from pymongo import MongoClient @@ -37,7 +37,7 @@ def get_collection_data(db_name: str, collection_name: str): db = mongo_client[db_name] # Check if the collection exists in the database if collection_name not in db.list_collection_names(): - return {"error": "Collection not found"} + raise HTTPException(status_code=404, detail="Collection not found") collection = db[collection_name] documents = list(collection.find({})) From 46931aa6abbc8bf3a4b4890b1ddd24da905ab848 Mon Sep 17 00:00:00 2001 From: shreddd Date: Thu, 12 Jun 2025 14:21:15 -0700 Subject: [PATCH 6/8] Add API endpoints --- src/server.py | 255 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 238 insertions(+), 17 deletions(-) diff --git a/src/server.py b/src/server.py index 63e88aa..37875e1 100644 --- a/src/server.py +++ b/src/server.py @@ -1,7 +1,10 @@ -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Query import uvicorn from fastapi.responses import RedirectResponse from pymongo import MongoClient +from typing import Optional, Dict, Any +from pydantic import BaseModel, Field +import json # Connect to MongoDB. # TODO: Get these values from environment variables instead of hard-coding them. @@ -23,23 +26,16 @@ def get_health(): return {"web_server": "ok", "database": is_database_healthy} -# TODO: Delete this endpoint once we're confident in our database connection. -@app.get("/experimental/database_names") -def get_database_names(): - r"""Get the names of all databases in the MongoDB server.""" - db_names = mongo_client.list_database_names() - return {"database_names": db_names} +@app.get("/bertron") +def get_all_entities(): + r"""Get all documents from the entities collection.""" + db = mongo_client["bertron"] + + # Check if the collection exists + if "entities" not in db.list_collection_names(): + raise HTTPException(status_code=404, detail="Entities collection not found") - -@app.get("/database/{db_name}/{collection_name}") -def get_collection_data(db_name: str, collection_name: str): - r"""Get all documents from a specified collection in a specified database.""" - db = mongo_client[db_name] - # Check if the collection exists in the database - if collection_name not in db.list_collection_names(): - raise HTTPException(status_code=404, detail="Collection not found") - - collection = db[collection_name] + collection = db["entities"] documents = list(collection.find({})) # Remove the MongoDB '_id' field from each document for JSON serialization @@ -49,5 +45,230 @@ def get_collection_data(db_name: str, collection_name: str): return {"documents": documents} +class MongoDBQuery(BaseModel): + filter: Dict[str, Any] = Field(default={}, description="MongoDB find query filter") + projection: Optional[Dict[str, Any]] = Field(default=None, description="Fields to include or exclude") + skip: Optional[int] = Field(default=0, ge=0, description="Number of documents to skip") + limit: Optional[int] = Field(default=100, ge=1, le=1000, description="Maximum number of documents to return") + sort: Optional[Dict[str, int]] = Field(default=None, description="Sort criteria (1 for ascending, -1 for descending)") + + +@app.post("/bertron/find") +def find_entities( + query: MongoDBQuery +): + r"""Execute a MongoDB find operation on the entities collection with filter, projection, skip, limit, and sort options. + + Example query body: + { + "filter": {"field": "value", "number_field": {"$gt": 100}}, + "projection": {"field1": 1, "field2": 1}, + "skip": 0, + "limit": 100, + "sort": {"field1": 1, "field2": -1} + } + """ + db = mongo_client["bertron"] + + # Check if the collection exists + if "entities" not in db.list_collection_names(): + raise HTTPException(status_code=404, detail="Entities collection not found") + + collection = db["entities"] + + try: + # Execute find with query parameters + cursor = collection.find( + filter=query.filter, + projection=query.projection + ) + + # Apply skip, limit, and sort if provided + if query.sort: + cursor = cursor.sort(list(query.sort.items())) + if query.skip: + cursor = cursor.skip(query.skip) + if query.limit: + cursor = cursor.limit(query.limit) + + # Convert cursor to list and remove MongoDB _id + documents = list(cursor) + for doc in documents: + doc.pop("_id", None) + + return {"documents": documents, "count": len(documents)} + + except Exception as e: + raise HTTPException(status_code=400, detail=f"Query error: {str(e)}") + + +@app.get("/bertron/geo/nearby") +def find_nearby_entities( + latitude: float = Query(..., ge=-90, le=90, description="Center latitude in degrees"), + longitude: float = Query(..., ge=-180, le=180, description="Center longitude in degrees"), + radius_meters: float = Query(..., gt=0, description="Search radius in meters") +): + r"""Find entities within a specified radius of a geographic point using MongoDB's $near operator. + + This endpoint uses MongoDB's geospatial $near query which requires a 2dsphere index + on the coordinates field for optimal performance. + + Example: /bertron/geo/nearby?latitude=47.6062&longitude=-122.3321&radius_meters=10000 + """ + db = mongo_client["bertron"] + + # Check if the collection exists + if "entities" not in db.list_collection_names(): + raise HTTPException(status_code=404, detail="Entities collection not found") + + collection = db["entities"] + + try: + # Build the $near geospatial query + geo_filter = { + "coordinates": { + "$near": { + "$geometry": { + "type": "Point", + "coordinates": [longitude, latitude] # MongoDB uses [lng, lat] format + }, + "$maxDistance": radius_meters + } + } + } + + # Execute find with geospatial filter and fixed projection + cursor = collection.find( + filter=geo_filter, + projection={"id": 1, "name": 1, "uri": 1, "ber_data_source": 1, "coordinates": 1} + ) + + # Convert cursor to list and remove MongoDB _id + documents = list(cursor) + for doc in documents: + doc.pop("_id", None) + + return { + "documents": documents, + "count": len(documents), + "query_type": "nearby", + "center": { + "latitude": latitude, + "longitude": longitude + }, + "radius_meters": radius_meters + } + + except Exception as e: + raise HTTPException(status_code=400, detail=f"Nearby query error: {str(e)}") + + +@app.get("/bertron/geo/bbox") +def find_entities_in_bounding_box( + southwest_lat: float = Query(..., ge=-90, le=90, description="Southwest corner latitude"), + southwest_lng: float = Query(..., ge=-180, le=180, description="Southwest corner longitude"), + northeast_lat: float = Query(..., ge=-90, le=90, description="Northeast corner latitude"), + northeast_lng: float = Query(..., ge=-180, le=180, description="Northeast corner longitude") +): + r"""Find entities within a bounding box using MongoDB's $geoWithin operator. + + This endpoint finds all entities whose coordinates fall within the specified + rectangular bounding box defined by southwest and northeast corners. + + Example: /bertron/geo/bbox?southwest_lat=47.5&southwest_lng=-122.4&northeast_lat=47.7&northeast_lng=-122.2 + """ + db = mongo_client["bertron"] + + # Check if the collection exists + if "entities" not in db.list_collection_names(): + raise HTTPException(status_code=404, detail="Entities collection not found") + + collection = db["entities"] + + try: + # Validate bounding box coordinates + if southwest_lat >= northeast_lat: + raise HTTPException(status_code=400, detail="Southwest latitude must be less than northeast latitude") + if southwest_lng >= northeast_lng: + raise HTTPException(status_code=400, detail="Southwest longitude must be less than northeast longitude") + + # Build the $geoWithin bounding box query + geo_filter = { + "coordinates": { + "$geoWithin": { + "$box": [ + [southwest_lng, southwest_lat], # MongoDB uses [lng, lat] format + [northeast_lng, northeast_lat] + ] + } + } + } + + # Execute find with geospatial filter and fixed projection + cursor = collection.find( + filter=geo_filter, + projection={"id": 1, "name": 1, "uri": 1, "ber_data_source": 1, "coordinates": 1} + ) + + # Convert cursor to list and remove MongoDB _id + documents = list(cursor) + for doc in documents: + doc.pop("_id", None) + + return { + "documents": documents, + "count": len(documents), + "query_type": "bounding_box", + "bounding_box": { + "southwest": { + "latitude": southwest_lat, + "longitude": southwest_lng + }, + "northeast": { + "latitude": northeast_lat, + "longitude": northeast_lng + } + } + } + + except Exception as e: + raise HTTPException(status_code=400, detail=f"Bounding box query error: {str(e)}") + + +@app.get("/bertron/{id}") +def get_entity_by_id(id: str): + r"""Get a single entity by its ID. + + Example: /bertron/emsl:12345 + """ + db = mongo_client["bertron"] + + # Check if the collection exists + if "entities" not in db.list_collection_names(): + raise HTTPException(status_code=404, detail="Entities collection not found") + + collection = db["entities"] + + try: + # Find the entity by ID with fixed projection + document = collection.find_one( + filter={"id": id}, + ) + + if not document: + raise HTTPException(status_code=404, detail=f"Entity with id '{id}' not found") + + # Remove MongoDB _id + document.pop("_id", None) + + return document + + except HTTPException: + # Re-raise HTTP exceptions + raise + except Exception as e: + raise HTTPException(status_code=400, detail=f"Query error: {str(e)}") + + if __name__ == "__main__": uvicorn.run(app, host="0.0.0.0", port=8000) From 28f9bafd7c475297f84d602f9169d91fcde376e5 Mon Sep 17 00:00:00 2001 From: shreddd Date: Thu, 12 Jun 2025 14:35:52 -0700 Subject: [PATCH 7/8] ruff formatting --- src/server.py | 187 +++++++++++++++++++++++++++++--------------------- 1 file changed, 110 insertions(+), 77 deletions(-) diff --git a/src/server.py b/src/server.py index 37875e1..34bf05b 100644 --- a/src/server.py +++ b/src/server.py @@ -4,7 +4,6 @@ from pymongo import MongoClient from typing import Optional, Dict, Any from pydantic import BaseModel, Field -import json # Connect to MongoDB. # TODO: Get these values from environment variables instead of hard-coding them. @@ -30,7 +29,7 @@ def get_health(): def get_all_entities(): r"""Get all documents from the entities collection.""" db = mongo_client["bertron"] - + # Check if the collection exists if "entities" not in db.list_collection_names(): raise HTTPException(status_code=404, detail="Entities collection not found") @@ -47,18 +46,24 @@ def get_all_entities(): class MongoDBQuery(BaseModel): filter: Dict[str, Any] = Field(default={}, description="MongoDB find query filter") - projection: Optional[Dict[str, Any]] = Field(default=None, description="Fields to include or exclude") - skip: Optional[int] = Field(default=0, ge=0, description="Number of documents to skip") - limit: Optional[int] = Field(default=100, ge=1, le=1000, description="Maximum number of documents to return") - sort: Optional[Dict[str, int]] = Field(default=None, description="Sort criteria (1 for ascending, -1 for descending)") + projection: Optional[Dict[str, Any]] = Field( + default=None, description="Fields to include or exclude" + ) + skip: Optional[int] = Field( + default=0, ge=0, description="Number of documents to skip" + ) + limit: Optional[int] = Field( + default=100, ge=1, le=1000, description="Maximum number of documents to return" + ) + sort: Optional[Dict[str, int]] = Field( + default=None, description="Sort criteria (1 for ascending, -1 for descending)" + ) @app.post("/bertron/find") -def find_entities( - query: MongoDBQuery -): +def find_entities(query: MongoDBQuery): r"""Execute a MongoDB find operation on the entities collection with filter, projection, skip, limit, and sort options. - + Example query body: { "filter": {"field": "value", "number_field": {"$gt": 100}}, @@ -69,20 +74,17 @@ def find_entities( } """ db = mongo_client["bertron"] - + # Check if the collection exists if "entities" not in db.list_collection_names(): raise HTTPException(status_code=404, detail="Entities collection not found") collection = db["entities"] - + try: # Execute find with query parameters - cursor = collection.find( - filter=query.filter, - projection=query.projection - ) - + cursor = collection.find(filter=query.filter, projection=query.projection) + # Apply skip, limit, and sort if provided if query.sort: cursor = cursor.sort(list(query.sort.items())) @@ -90,39 +92,43 @@ def find_entities( cursor = cursor.skip(query.skip) if query.limit: cursor = cursor.limit(query.limit) - + # Convert cursor to list and remove MongoDB _id documents = list(cursor) for doc in documents: doc.pop("_id", None) - + return {"documents": documents, "count": len(documents)} - + except Exception as e: raise HTTPException(status_code=400, detail=f"Query error: {str(e)}") @app.get("/bertron/geo/nearby") def find_nearby_entities( - latitude: float = Query(..., ge=-90, le=90, description="Center latitude in degrees"), - longitude: float = Query(..., ge=-180, le=180, description="Center longitude in degrees"), - radius_meters: float = Query(..., gt=0, description="Search radius in meters") + latitude: float = Query( + ..., ge=-90, le=90, description="Center latitude in degrees" + ), + longitude: float = Query( + ..., ge=-180, le=180, description="Center longitude in degrees" + ), + radius_meters: float = Query(..., gt=0, description="Search radius in meters"), ): r"""Find entities within a specified radius of a geographic point using MongoDB's $near operator. - - This endpoint uses MongoDB's geospatial $near query which requires a 2dsphere index + + This endpoint uses MongoDB's geospatial $near query which requires a 2dsphere index on the coordinates field for optimal performance. - + Example: /bertron/geo/nearby?latitude=47.6062&longitude=-122.3321&radius_meters=10000 """ db = mongo_client["bertron"] - + # Check if the collection exists if "entities" not in db.list_collection_names(): raise HTTPException(status_code=404, detail="Entities collection not found") collection = db["entities"] - + try: # Build the $near geospatial query geo_filter = { @@ -130,139 +136,166 @@ def find_nearby_entities( "$near": { "$geometry": { "type": "Point", - "coordinates": [longitude, latitude] # MongoDB uses [lng, lat] format + "coordinates": [ + longitude, + latitude, + ], # MongoDB uses [lng, lat] format }, - "$maxDistance": radius_meters + "$maxDistance": radius_meters, } } } - + # Execute find with geospatial filter and fixed projection cursor = collection.find( filter=geo_filter, - projection={"id": 1, "name": 1, "uri": 1, "ber_data_source": 1, "coordinates": 1} + projection={ + "id": 1, + "name": 1, + "uri": 1, + "ber_data_source": 1, + "coordinates": 1, + }, ) - + # Convert cursor to list and remove MongoDB _id documents = list(cursor) for doc in documents: doc.pop("_id", None) - + return { "documents": documents, "count": len(documents), "query_type": "nearby", - "center": { - "latitude": latitude, - "longitude": longitude - }, - "radius_meters": radius_meters + "center": {"latitude": latitude, "longitude": longitude}, + "radius_meters": radius_meters, } - + except Exception as e: raise HTTPException(status_code=400, detail=f"Nearby query error: {str(e)}") @app.get("/bertron/geo/bbox") def find_entities_in_bounding_box( - southwest_lat: float = Query(..., ge=-90, le=90, description="Southwest corner latitude"), - southwest_lng: float = Query(..., ge=-180, le=180, description="Southwest corner longitude"), - northeast_lat: float = Query(..., ge=-90, le=90, description="Northeast corner latitude"), - northeast_lng: float = Query(..., ge=-180, le=180, description="Northeast corner longitude") + southwest_lat: float = Query( + ..., ge=-90, le=90, description="Southwest corner latitude" + ), + southwest_lng: float = Query( + ..., ge=-180, le=180, description="Southwest corner longitude" + ), + northeast_lat: float = Query( + ..., ge=-90, le=90, description="Northeast corner latitude" + ), + northeast_lng: float = Query( + ..., ge=-180, le=180, description="Northeast corner longitude" + ), ): r"""Find entities within a bounding box using MongoDB's $geoWithin operator. - - This endpoint finds all entities whose coordinates fall within the specified + + This endpoint finds all entities whose coordinates fall within the specified rectangular bounding box defined by southwest and northeast corners. - + Example: /bertron/geo/bbox?southwest_lat=47.5&southwest_lng=-122.4&northeast_lat=47.7&northeast_lng=-122.2 """ db = mongo_client["bertron"] - + # Check if the collection exists if "entities" not in db.list_collection_names(): raise HTTPException(status_code=404, detail="Entities collection not found") collection = db["entities"] - + try: # Validate bounding box coordinates if southwest_lat >= northeast_lat: - raise HTTPException(status_code=400, detail="Southwest latitude must be less than northeast latitude") + raise HTTPException( + status_code=400, + detail="Southwest latitude must be less than northeast latitude", + ) if southwest_lng >= northeast_lng: - raise HTTPException(status_code=400, detail="Southwest longitude must be less than northeast longitude") - + raise HTTPException( + status_code=400, + detail="Southwest longitude must be less than northeast longitude", + ) + # Build the $geoWithin bounding box query geo_filter = { "coordinates": { "$geoWithin": { "$box": [ - [southwest_lng, southwest_lat], # MongoDB uses [lng, lat] format - [northeast_lng, northeast_lat] + [ + southwest_lng, + southwest_lat, + ], # MongoDB uses [lng, lat] format + [northeast_lng, northeast_lat], ] } } } - + # Execute find with geospatial filter and fixed projection cursor = collection.find( filter=geo_filter, - projection={"id": 1, "name": 1, "uri": 1, "ber_data_source": 1, "coordinates": 1} + projection={ + "id": 1, + "name": 1, + "uri": 1, + "ber_data_source": 1, + "coordinates": 1, + }, ) - + # Convert cursor to list and remove MongoDB _id documents = list(cursor) for doc in documents: doc.pop("_id", None) - + return { "documents": documents, "count": len(documents), "query_type": "bounding_box", "bounding_box": { - "southwest": { - "latitude": southwest_lat, - "longitude": southwest_lng - }, - "northeast": { - "latitude": northeast_lat, - "longitude": northeast_lng - } - } + "southwest": {"latitude": southwest_lat, "longitude": southwest_lng}, + "northeast": {"latitude": northeast_lat, "longitude": northeast_lng}, + }, } - + except Exception as e: - raise HTTPException(status_code=400, detail=f"Bounding box query error: {str(e)}") + raise HTTPException( + status_code=400, detail=f"Bounding box query error: {str(e)}" + ) @app.get("/bertron/{id}") def get_entity_by_id(id: str): r"""Get a single entity by its ID. - + Example: /bertron/emsl:12345 """ db = mongo_client["bertron"] - + # Check if the collection exists if "entities" not in db.list_collection_names(): raise HTTPException(status_code=404, detail="Entities collection not found") collection = db["entities"] - + try: # Find the entity by ID with fixed projection document = collection.find_one( filter={"id": id}, ) - + if not document: - raise HTTPException(status_code=404, detail=f"Entity with id '{id}' not found") - + raise HTTPException( + status_code=404, detail=f"Entity with id '{id}' not found" + ) + # Remove MongoDB _id document.pop("_id", None) - + return document - + except HTTPException: # Re-raise HTTP exceptions raise From 6be38532cd6aac105830abcef976513e8138c607 Mon Sep 17 00:00:00 2001 From: shreddd Date: Thu, 12 Jun 2025 14:44:13 -0700 Subject: [PATCH 8/8] fix merge conflict --- docker-compose.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/docker-compose.yml b/docker-compose.yml index 6d96f8d..06811e5 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -50,8 +50,6 @@ services: - mongo # Run ingest with data dir mounted to /data command: ["uv", "run", "python", "/app/mongodb/ingest_data.py", "--mongo-uri", "mongodb://admin:root@mongo:27017", "--input", "/data"] -<<<<<<< HEAD -======= test: # Use the same container image as the app service for consistency @@ -62,7 +60,6 @@ services: - app - mongo command: ["uv", "run", "pytest", "-v"] ->>>>>>> main volumes: # Define a named volume that will contain MongoDB data.