Возникли проблемы с поиском/или реализацией правильного метода mongoDb для поиска и обновления вложенного документа

Я пытаюсь обновить определенное поле в поддокументе на основе его идентификатора и идентификатора родительского документа. Я новичок в этом, поэтому я могу неправильно понимать документацию mongoDb, но, насколько я могу судить, findOneAndUpdate должен работать. Я также пробовал просто обновить, updateOne, а также findByIdAndUpdate. Ничто из того, что я пробовал, не обновило мой объект.

Я пытаюсь обновить значение рейтинга в конкретном объекте в массиве saveBeers.

Вот моя модель:

{
    "_id": {
        "$oid": "5c97cf50cc81525a75eb6c19"
    },
    "email": "[email protected]",
    "password": "$2b$10$6ixbu2Ka.Zj0eE5kF21MLO6CiMblgu4D6IHiC7Ta52o.cZFMNw1Mm",
    "__v": 0,
    "savedBeers": [
        {
            "id": 2,
            "comment": null,
            "rating": 0
        },
        {
            "id": 4,
            "comment": null,
            "rating": 0
        }
    ]
}

Внешний интерфейс:

function addRating(beerId, ratingValue){
    let userId= localStorage.userId
    console.log(beerId, userId, ratingValue);
    $.ajax({
        type: "PUT",
        url: `/user/${userId}/${beerId}/${ratingValue}`,
        success: addRatingSuccess,
        error: addRatingError
    });
    function addRatingSuccess(response) {
        console.log("added", response);
    }
    function addRatingError() {
        console.log("error");    
    }
}

Серверная часть userController.js:

 addRating:(req,res)=>{
            console.log(req.params);
            req.params.beerId = parseInt(req.params.beerId)
            req.params.ratingValue = parseInt(req.params.ratingValue)
            db.User.findOneAndUpdate(
                 {_id: ObjectId(req.params.userId), "savedBeers.id": req.params.beerId },
                { $set: { 'savedBeers.$.rating' : req.params.ratingValue } },
                {new:true})
                .exec(function (err, doc){
                    if (err){
                        console.log(err);
                        res.json({
                            "error": err
                        })
                    } else {
                        console.log(doc);
                        res.json({
                            doc
                        })
                    }
                }) 
        }

Вот ответ, который я получаю в интерфейсе:

added 
{doc: {…}}
doc:
email: "[email protected]"
savedBeers: Array(2)
0: {id: 2, comment: null, rating: 0}
1: {id: 4, comment: null, rating: 0}
length: 2
__proto__: Array(0)
__v: 0
_id: "5c97cf50cc81525a75eb6c19"
__proto__: Object
__proto__: Object

И бэкэнд:

{ userId: '5c97cf50cc81525a75eb6c19', beerId: 4, ratingValue: 3 }
{ savedBeers:
   [ { id: 2, comment: null, rating: 0 },
     { id: 4, comment: null, rating: 0 } ],
  _id: 5c97cf50cc81525a75eb6c19,
  email: '[email protected]',
  __v: 0 }


Большое спасибо, что нашли время. Пожалуйста, дайте мне знать, если есть какая-либо другая информация, которая была бы полезна.


person Langdon Froker    schedule 28.03.2019    source источник
comment
Я тоже пробовал это решение. Тоже не работает. Отредактировал мой пост, чтобы отразить это.   -  person Langdon Froker    schedule 29.03.2019
comment
Работает для остальных людей в мире и делает это уже много лет. Также обратите внимание, что вы не можете использовать предикат нескольких полей с findByIdAndUpdate(), так как он принимает только значение _id только. Вместо этого вы хотите findOneAndUpdate(), и вы также обычно хотите new: true с любым из них. Не откроется снова, так как связанный ответ действительно является ответом, просто вы все еще делаете что-то неправильно. Прочтите ответы и связанную документацию еще раз.   -  person Neil Lunn    schedule 30.03.2019
comment
Да, это странно, потому что это не работает. Понял про findOneAndUpdate, и новое: true. На мой взгляд, это: db.your_collection.update( { _id: ObjectId("your_objectid"), "Statuses.Type": 1 }, { $set: { "Statuses.$.Timestamp": "new timestamp" } } ) выглядит почти так же, как это: db.User.findOneAndUpdate( {_id: ObjectId(req.params.userId), "savedBeers.id": req.params.beerId }, { $set: { 'savedBeers.$.rating' : req.params.ratingValue } }, { new:true})}   -  person Langdon Froker    schedule 30.03.2019
comment
Самое последнее, что вы сейчас показываете в своем посте, — это ответ, который вы получаете. См. n: 0. Это означает, что ничего не совпало. Вы используете простой драйвер узла, поэтому такие вещи, как findByIdAndUpdate, даже недействительны.   -  person Neil Lunn    schedule 31.03.2019
comment
"savedBeers.id": parseIntr(req.params.beerId) - Это ваша проблема все время, так как вам нужно parseInt(). Столь же важно, как и ObjectId(), где оно используется, и по той же причине req.params являются строками**, поэтому вам нужно их привести. Что меня бросило, так это то, что вы использовали findByIdAndUpdate() в вопросе, который является методом мангуста, а не частью этого драйвера. В Mongoose есть определения схемы, которые автоматически приводят значения в предикатах запроса к ожидаемому типу. Для всего остального вы делаете это вручную.   -  person Neil Lunn    schedule 31.03.2019
comment
Ok. Извините, я не редактировал свой пост со вчерашнего дня. В моем последнем ответе я показываю, что больше не использую findByIdAndUpdate. Я отредактировал свой пост с помощью parseInt() и моего текущего ответа. Спасибо за помощь.   -  person Langdon Froker    schedule 31.03.2019


Ответы (1)


Похоже, вам не хватает «.rating» после «savedBeers.$» в «{ $set: { 'savedBeers.$': req.params.ratingValue }»

Таким образом, эта строка должна быть "{ $set: { 'savedBeers.$.rating': req.params.ratingValue }"

person Umut    schedule 28.03.2019
comment
Спасибо за ответ. Я тоже это пробовал. Тот же результат. - person Langdon Froker; 28.03.2019