Home > OS >  findOneAndUpdate used for update one element of array
findOneAndUpdate used for update one element of array

Time:11-23

I have one db like this:

{
    _id: ObjectId('637bbfd595f55f2f4673ec41'),
    uuid: '63068d38c172ccfc2c5bc86e',
    title: 'Test Board1',
    description: 'cddsvsdv',
    icon: 'mat_outline:groups',
    lists: [{
            title: 'Monday',
            boardId: '637bbfd595f55f2f4673ec41',
            position: 65536,
            cards: [],
            _id: ObjectId('637cbfcac1dfe0fb0841d0f3'),
            createdAt: ISODate('2022-11-22T12:25:46.953Z'),
            updatedAt: ISODate('2022-11-22T12:25:46.953Z')
        },
        {
            title: 'Tuesday',
            boardId: '637bbfd595f55f2f4673ec41',
            position: 65536,
            cards: [],
            _id: ObjectId('637cbfcac1dfe0fb0841d0f8'),
            createdAt: ISODate('2022-11-22T12:25:46.966Z'),
            updatedAt: ISODate('2022-11-22T15:36:26.625Z')
        }
    ],
    labels: [],
    updatedAt: ISODate('2022-11-22T15:36:26.625Z'),
    createdAt: ISODate('2022-11-21T18:13:41.041Z'),
    __v: 0
}

and I would like to modify one item inside the array LISTS by the ID reference. I write this:

const BoardUpdate = await context.di.model.BoardsUser.findOneAndUpdate(
    {
        lists: {
            $elemMatch:
            {
                _id: mongoose.Types.ObjectId(input.id),
            }
        },
    },
    {
        $set: {
            'lists.$[el].title': input.title
        }
    },
    {
        arrayFilters:[{
            'el._id': mongoose.Types.ObjectId(input.id)
        }]
    }
);

in the input I have the data passed by http:

"vInput": {
    "id": "637cbfcac1dfe0fb0841d0f8",
    "boardId": "637bbfd595f55f2f4673ec41",
    "title": "Tuesday111",
    "position": 65536,
    "cards": []
}

so after the update I'm able to modify the title, but the question is: How can pass all the data of the object VInput? because inside the array CARDS the are more data and I think is possible to pass all the object. when I try to modify the $set line like this:

$set: {
    'lists.$[el]': input
}

I receive this error:

"Updating the path 'lists.$[el].updatedAt' would create a conflict at 'lists.$[el]

I don't know how to solve this.

CodePudding user response:

The issue is that mongoose cannot replace an element in an array when { timestamps: true } is set in the mongoose schema.

There are a few workarounds:

  • Get rid of { timestamps: true } in the lists array in the mongoose schema.
  • Set the update operator to update each field:
    $set: {
       'lists.$[el].title': input.title,
       'lists.$[el].position': input.position,
       'lists.$[el].cards': input.cards,
        ...
   } 
  • Depending on the use case, you may be creating large documents, which should be avoided. In this case you should create a lists collection. This would make the updating lists much simpler
  • Related