mongodbnosqlpymongofastapiodm

MongoDB - Find and update element of array if object that is nested inside of array matches query


I have a FastAPI app using PyMongo and Beanie.

I want to filter the recommendations document array given an artist id, and update it's approve, notes and feedback keys.

Important

artist is an optional link to another collection:

artist: Optional[Link[ArtistCollection]]

     {
         "_id": "65a16b0469f8f0425e8d47a9",
         "created_at": "2024-01-12T16:38:28.403000",
         "status": "open",
         "notes": null,
         "event": null,
         "recomendations": [
             {
                 "approve": null,
                 "disapprove": null,
                 "notes": "",
                 "feedback": "",
                 "score": null,
                 "artist": {
                     "id": "182957",
                     ..., # Other Fields
                 }
             },
             ...,
         ]
      }

I've tried the following, and got no results:

    recommendation = await Recomendations.find_one(
        {"_id": ObjectId(recomendation_id)},
        fetch_links=True,
    )
    updated_document = await recommendation.update(
        {"$set": {
            "artist_recomendations.$[elem].approve": datetime.now(),
            "artist_recomendations.$[elem].notes": artist_recomendation.notes,
            "artist_recomendations.$[elem].feedback": artist_recomendation.feedback,
        }},
        array_filters=[{"elem.artist.$id": artist_id}]
    )

    return updated_document

Solution

  • Ok, found the issue, I had to filter by artist, and use a DBRef object to have the correct assignment.

    
        try:
            result = await Recomendations.find_one({"_id": PydanticObjectId(recomendation_id)})
            if not result:
                raise HTTPException(status_code=404, detail="Recomendation not found")
    
            await result.update(
                {
                    "$set": {
                        "artist_recomendations.$[x].approve": datetime.now(),
                        "artist_recomendations.$[x].notes": artist_recomendation.notes,
                        "artist_recomendations.$[x].feedback": artist_recomendation.feedback,
                    },
                },
                array_filters=[{"x.artist": DBRef(collection=('artists'), id=artist_id)}], 
            )
            return result
        except Exception as e:
            print(e)
            raise HTTPException(status_code=404, detail="Item not found")