1

I have such Article-documents:

{
    "_id" : "rNiwdR8tFwbTdr2oX",
    "createdAt" : ISODate("2018-08-25T12:23:25.797Z"),
    "title" : "Happy",
    "lines" : [ 
        {
            "id" : "5efa6ad451048a0a1807916c",
            "text" : "Test 1",
            "align" : "left",
            "indent" : 0
        }, 
        {
            "id" : "ae644f39553d46f85c6e1be9",
            "text" : "Test 2"
        }, 
        {
            "id" : "829f874878dfd0b47e9441c2",
            "text" : "Test 3"
        }, 
        {
            "id" : "d0a46ef175351ae1dec70b9a",
            "text" : "Test 4"
        }, 
        {
            "id" : "9bbc8c8d01bc7029220bed3f",
            "text" : "Test 5"
        }, 
        {
            "id" : "6b5c02996a830f807e4d8e35",
            "text" : "Test 6",
            "indent" : 0
        }
    ]
}

I need to update some Lines. For example I have array with ids of the line which must be updated.

let lineIds = [
    "5efa6ad451048a0a1807916c", 
    "829f874878dfd0b47e9441c2", 
    "6b5c02996a830f807e4d8e35"
];

So I try to update attributes "attr" for the "lines" and I do following:

    'articles.updateLines': function (articleId, lineIds, attr, value) {
        return Articles.update({
                '_id': articleId,
                'lines.id': { $in: lineIds }
            },
            {
                $set: {
                    ['lines.$.' + attr]: value
                }
            },
            { multi: true }
        );
    }

The problem is that just the first line (with id="5efa6ad451048a0a1807916c") is updated. Any ideas? Thanks! :)

podeig
  • 2,597
  • 8
  • 36
  • 60

2 Answers2

2

You can use $[]. This will works only MongoDB version 3.6 and above.

Refer link : https://docs.mongodb.com/manual/reference/operator/update/positional-all/

 You can also see this stackoverflow question reference: 

How to add new key value or change the key's value inside a nested array in MongoDB?

You can convert below query in your function

 db.col.update(
  { '_id':"rNiwdR8tFwbTdr2oX", },
  { $set: { "lines.$[elem].text" : "hello" } },     
  {  arrayFilters: [ { "elem.id": { $in: lineIds } } ],
  multi: true
 })
Anushka Ahir
  • 136
  • 7
1

'lines.id': { $in: lineIds }

This won't work, because lines is an array.

What I understand from your question, you can prepare a new array with proper processing and replace the lines array with the new one. Here is an idea how to do this:

'articles.updateLines': function (articleId, lineIds, attr, value) {
    let lines = Articles.findOne(articleId).lines;
    // prepare a new array with right elements
    let newArray = [];
    for(let i=0; i<lines.length; i++){
        if(lineIds.includes(lines[i].id)){
            newArray.push(value)
        }
        else newArray.push(lines[i])
    }
    return Articles.update({
            '_id': articleId,
        },
        {
            $set: {
                lines: newArray
            }
        }
    );
}
Mostafiz Rahman
  • 8,169
  • 7
  • 57
  • 74
  • Hi, Thank you for the answer. It works well. I forgot about that I can update subdocuments on the client and update it then. I just removed newArray and used lines all the way. if(lineIds.includes(lines[i].id)){ lines[i] = { ...lines[i], [attr]: value }; } so it just was need for modifing. Thanks! :) – podeig Dec 28 '18 at 10:26