Search code examples
arraysmongodbobjectnestedpymongo

MongoDB query and update single object inside nested array by ID?


From this example document:

...
{
    "_id": ObjectId("5a934e000102030405000000"),
    "guild_id": 1234,
    "members": [
        ...
        {
            "member_id": 002,
            "name": "John Doe"
        },
        ...
    ]
}
...

I want to fetch an individual member object from the nested array so that I will be returned:

{"member_id": 002, "name": "John Doe"}

with which I can read in the member info.

How might one query by "member_id" like with 002 and get the desired result above? And with this, how would you also update the member "name" as well? Preferably in Python syntax, please, but any is fine as well.


Solution

  • aggregate

    db.collection.aggregate([
      {
        "$match": {
          "members.member_id": "001"
        }
      },
      {
        "$unwind": "$members"
      },
      {
        "$match": {
          "members.member_id": "001"
        }
      },
      {
        "$replaceWith": "$members"
      }
    ])
    

    mongoplayground


    update

    db.collection.update({
      "members.member_id": "001"
    },
    {
      "$set": {
        "members.$.name": "John"
      }
    },
    {
      "multi": false,
      "upsert": false
    })
    

    mongoplayground


    python(fastapi) Edit this by yourself

    from fastapi import FastAPI, Request, status, HTTPException
    from fastapi.responses import HTMLResponse
    from fastapi.staticfiles import StaticFiles
    from fastapi.templating import Jinja2Templates
    from pymongo import MongoClient
    from fastapi.encoders import jsonable_encoder
    from fastapi.exceptions import RequestValidationError
    from fastapi.responses import JSONResponse
    from pydantic import BaseModel
    
    CONNECTION_STRING = "mongodb://localhost"
    try:
        client = MongoClient(CONNECTION_STRING, serverSelectionTimeoutMS=3000)
        print('Connected ! Mongo version is', client.server_info()['version'])
    except:
        print('Disconnected !')
    
    app = FastAPI()
    app.mount("/static", StaticFiles(directory="static"), name="static")
    @app.exception_handler(RequestValidationError)
    async def validation_exception_handler(request: Request, exc: RequestValidationError):
        return JSONResponse(
            status_code=status.HTTP_422_UNPROCESSABLE_ENTITY,
            content=jsonable_encoder({"detail": exc.errors(), "body": exc.body}),
        )
    
    templates = Jinja2Templates(directory="static")
    
    @app.get("/")
    async def root():
        db = get_database()
        c = db['key'].find({"_id":2})
        if (c):
            return {"message": c[0]}
        return {"message": c}
    
    @app.get("/get/{id}")
    async def root(id: int):
        db = get_database()
        c = list(db['key'].find({"_id":id}))
        return {"message": c}
    
    def get_database():
        return client['test']
        
    # This is added so that many files can reuse the function get_database()
    if __name__ == "__main__":    
        print('__main__ !')
        # Get the database
        dbname = get_database()