Search code examples
mongodbgomgo

How to return embedded document with ID of


I have a MongoDB collection with an example document like this:

Mongo example document

What I want to do (as you can see from the actual code) is to update a role field in members.x.role where members.x.id equals given ID (ID is UUID so it's unique; this part of code works without problem) and then I want to return that members.x. But the problem is that it always returns first member instead of the one that has been just updated. I've tried some methods of mgo and found Distinct() be closest to my expectations, but that doesn't work as I want.

My question is how can I return member embedded document with specified ID?

I've already looked on this and this but it didn't help me.

func (r MongoRepository) UpdateMemberRole(id string, role int8) (*Member, error) {
    memberQuery := &bson.M{"members": &bson.M{"$elemMatch": &bson.M{"id": id}}}
    change := &bson.M{"members.$.role": role}

    err := r.db.C("groups").Update(memberQuery, &bson.M{"$set": &change})
    if err == mgo.ErrNotFound {
        return nil, fmt.Errorf("member with ID '%s' does not exist", id)
    }

    // FIXME: Retrieve this member from query below. THIS ALWAYS RETURNS FIRST MEMBER!!!
    var member []Member
    r.db.C("groups").Find(&bson.M{"members.id": id}).Distinct("members.0", &member)

    return &member[0], nil
}

Solution

  • I found a workaround, it's not stricte Mongo query that is returning this embedded document, but this code is IMO more clear and understandable than some fancy Mongo query that fetches whole document anyway.

    func (r MongoRepository) UpdateMemberRole(id string, role int8) (*Member, error) {
        change := mgo.Change{
            Update: bson.M{"$set": bson.M{"members.$.role": role}},
            ReturnNew: true,
        }
    
        var updatedGroup Group
        _, err := r.db.C("groups").Find(bson.M{"members": bson.M{"$elemMatch": bson.M{"id": id}}}).Apply(change, &updatedGroup)
        if err == mgo.ErrNotFound {
            return nil, fmt.Errorf("member with ID '%s' does not exist", id)
        } else if err != nil {
            return nil, err
        }
    
        for _, member := range updatedGroup.Members {
            if member.Id == id {
                return &member, nil
            }
        }
    
        return nil, fmt.Errorf("weird error, Id cannot be found")
    }