10

I have document like

{
    id : 100,
    heros:[
        {
           nickname : "test",
           spells : [
             {spell_id : 61, level : 1},
             {spell_id : 1, level : 2}
           ]
        }
    ]
}

I can't $set spell's level : 3 with spell_id : 1 inside spells that inside heros with nickname "test. I tried this query:

db.test.update({"heros.nickname":"test", "heros.spells.spell_id":1}, 
{$set:{"heros.spells.$.level":3}});

Errror i see is

can't append to array using string field name [spells] Thanks for help.

2 Answers 2

12

You can only use the $ positional operator for single-level arrays. In your case, you have a nested array (heros is an array, and within that each hero has a spells array).

If you know the indexes of the arrays, you can use explicit indexes when doing an update, like:

> db.test.update({"heros.nickname":"test", "heros.spells.spell_id":1}, {$set:{"heros.0.spells.1.level":3}});
Sign up to request clarification or add additional context in comments.

Comments

3

Try something like this:

db.test.find({"heros.nickname":"test"}).forEach(function(x) {  
    bool match = false;
    for (i=0 ; i< x.heros[0].spells.length ; i++) {
        if (x.heros[0].spells[i].spell_id == 1) 
        {
            x.heros[0].spells[i].level = 3;
            match = true;
        }
    }
    if (match === true) db.test.update( { id: x.id }, x );
});

Apparently someone opened a ticket to add the ability to put a function inside the update clause, but it hasn't been addressed yet: https://jira.mongodb.org/browse/SERVER-458

5 Comments

Your code doesn't work. I think in x will be all document isn't it?
@DenisErmolin oops ... yeah, that was wrong. I took another shot at it (see update). x is the document, right, so I'm thinking you should be able to update it by the id property.
x.spells reference to spells but spells in heros array
It does work well for my, only need to change the variable from: bool match = false to $match = false, then use $match to reference.
@McGarnagle but this code will not be atomic as between find and update, suppose you find spell_id == 1, at index 1 and at the same time some other query added/removed embedded document at index 1, now what will happen is when your query will update in mongo, then it will put updated value at index 1, which will overwrite the document which got added/removed previously at index 1.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.