2

I have an object with the following form :

{
    "_id": ObjectId("4fa43f4d1cf26a6a8952adf1"),
    "userId": "1",
    "facebookId": "1234",
    "groups": [{
        "groupName": "testGroup",
        "members": [{
            "memberFirstName": "userFirstName",
            "memberLastName": "userLastName",
            "memberDetails": {
                "userId": "1",
                "faceBookId": "1234"
            }
        }]
    }]
}

It's a collection that holds for each user - its groups, with each group containing the group members... So the "groups" key is an array (or list), and so is the "members" key. (each user could have multiple groups, each group has multiple group members).

I'm having a hard time updating the object with a new group member, what I'm trying to do is :

db.collection.update({
    userId: "1"
}, {
    $push: {
        "groups.members": {
            membersDetails: {
                userId: "2",
                faceBookId: "54321"
            },
            memberFirstName: "UserB",
            memberLastName: "UserBLastName"
        }
    }
});

But it doesn't seem to work.

got the following error :

can't append to array using string field name [members]

I'm also trying to work with the Java driver, but that doesn't seem to work as well.

DBObject query = new BasicDBObject("userId", "1");

DBObject newMemberDetailsObj = new BasicDBObject();
newMemberDetailsObj.put("userId", "2");
newMemberDetailsObj.put("faceBookId", "54321");

DBObject newMemberObj = new BasicDBObject();
newMemberObj.put("memberFirstName", "userB");
newMemberObj.put("memberLastName", "UserBLastName");
newMemberObj.put("memberDetails", newMemberDetailsObj );

DBObject update = new BasicDBObject("$push", new BasicDBObject("members", newMemberObj));
update.put("groupName", "testGroup");       

DBObject maintain = new BasicDBObject("$push", new BasicDBObject("groups", update));

WriteResult newWr = coll.update(query, maintain);
Machavity
  • 30,841
  • 27
  • 92
  • 100
IRousso
  • 136
  • 2
  • 7
  • The current answers explain why you can't update the way you are trying. But I wanted to add that I think it would be a lot easier if you designed "groups" to be an object, where the key is the groupName and the value is the group object. Since you seem to want to access them frequently this way. – jdi May 04 '12 at 22:13
  • i will consider it, thanks for the advice! – IRousso May 04 '12 at 23:12

2 Answers2

4

This won't work because groups is an array, but you're referencing a property in it as if it were an object. You could access things like groups.0.members or groups.1.members because these refer to specific items in the array, but the groups object itself doesn't have a members attribute to append to.

I'm not totally sure what your update needs to do exactly, but you could add a filter on groups.groupName to your query, and then do $push with groups.$.members to append a member only to the group that matched.

http://www.mongodb.org/display/DOCS/Updating#Updating-The%24positionaloperator

mpobrien
  • 4,922
  • 1
  • 33
  • 35
4

It's because your user model can have multiple groups so you need to match a group in the filter and use the positional operator $ in the update. So your update would be something like this (untested):

db.collection.update({
    userId: "1",
    "groups.groupName": "testGroup" // match against the group here
}, {
    $push: {
        "groups.$.members": { // notice the use of the $ here
            membersDetails: {
                userId: "2",
                faceBookId: "54321"
            },
            memberFirstName: "UserB",
            memberLastName: "UserBLastName"
        }
    }
});

When you have an array of values, the positional operator basically says "at the position of the matched value in the array".

However, you can only do this one level of arrays deep, so you wouldn't be able to match a specific member in a specific group, for example - so you may want to break up your document into a number of simpler collections if you're going to need to do this sort of thing.

Russell
  • 12,261
  • 4
  • 52
  • 75