mongodbgomgomongo-go

Mongo-go how to use arrayFilter to find elem in "array of objects inside array of objects"


Lets imagine a JSON like:

"user": {
  "id": "1234",
  ...some fields,
  "achievements": [
    {
      "scope": "life achievements",
      "list": [
        {"_id": 1, "title": "some text", "gotAt": "some date"},
        {"_id": 2, "title": "some other text", "gotAt": "some date"}
      ]
    },
    {
      "scope": "sport achievements",
      "list": [
        {"_id": 1, "title": "sport", "gotAt": "some date"},
        {"_id": 2, "title": "some other sport", "gotAt": "some date"}
      ]
    },
    {
      "scope": "academic achievements",
      "list": [
        {"_id": 1, "title": "some text", "gotAt": "some date"},
        {"_id": 2, "title": "some other text", "gotAt": "some date"}
      ]
    },
  ]
}

I need to UPDATE for example the first life achievement (with id 1) using mongoDb and Golang driver Mongo-go for it

The problem is in the nesting level. I can get some array element by $ mongoDb operator, but here i need to identify every user achievement by the activity scope (life, sport, academic etc) and _id field of achievement. So I need to make a search inside an array of objects inside other array of objects.

Thats what ive done (it doesnt work anyway)

doc := coll.FindOneAndUpdate(
        context.Background(),
        bson.D{
            {"_id", "1234"},
            {"achievements.scope", "life achievements"},
            {"achievements.list._id", 1},
        },
        bson.D{
            {"$set", bson.D{
                {"achievements.$.list.$[elem].title", "some new test"},
            }},
        },
        options.FindOneAndUpdate().SetArrayFilters(options.ArrayFilters{
            Filters: append(make([]interface{}, 0), bson.D{
                {"elem", bson.D{
                    {"achievements.list._id", 1},
                }},
            }),
        }).SetReturnDocument(1),
    )

I expect this query to update only one element specified by "id" and "scope" fields. May be I use arrayFilters incorretly, or may be I set param of FindOneAndUpdate function incorrectly. Now it doesnt throw any error nor updates the document. Please help me


Solution

  • With the package go.mongodb.org/mongo-driver/mongo you can do it like this:

    coll.FindOneAndUpdate(
        context.Background(),
        bson.D{
            {"id", "1234"},
            {"achievements.scope", "life achievements"},
            {"achievements.list._id", 1},
        },
        bson.M{"$set": bson.M{"achievements.$.list.$[elem].title": "some new test"}},
        options.FindOneAndUpdate().SetArrayFilters(options.ArrayFilters{
            Filters: []interface{}{bson.M{"elem._id": 1}},
        }),
    )
    

    which "translates" to shell:

    db.user.findOneAndUpdate(
      {"id": "1234","achievements.scope": "life achievements","achievements.list._id": 1},
      {$set: {"achievements.$.list.$[elem].title": "some new test"}},
      {arrayFilters: [{"elem._id": 1}]}
    )