Почему я могу обновить одно поле, а не другое в MongoDB? (ОЗНАЧЕННЫЙ Стек) - PullRequest
0 голосов
/ 28 августа 2018

У меня есть два поля: "password_hash" и "password_token" в моей коллекции db.user mongoDB. Я могу обновить "password_hash" из API (curl, через экспресс-маршрут, в модель mongoose), но я не могу обновить "password_token", используя почти такой же код. Я могу изменить любой «вручную» из Studio3t, но это будет противоречить цели написания API. Я также думаю, что это означает, что это поведение не связано с индексами, валидаторами и т. Д. В коллекции базы данных, поскольку мне разрешено сохранять значения в любом поле. Когда я пытаюсь сделать то же самое из API, я не получаю сообщение об ошибке, только { ok: 0, n: 0, nModified: 0 } и не обновляемое поле.

Вот сокращенный документ:

"username" : "user1", 
"password_hash" : "$2a$10$pVTT8FS.WV.sba1wvVwYMu7hMqaGkP1toJx5PGMXrl/ZnLyLtqsYy", 
"password_token" : ""

Вот команды curl, которые я использую:

# curl -w '\n' -H "Content-Type: application/json" -X POST -d '{ "username": "user1"}' http://localhost:3000/users/save_hash
{"success":true,"message":"Saved a hash for user1."}

# curl -w '\n' -H "Content-Type: application/json" -X POST -d '{ "username": "user1"}' http://localhost:3000/users/reset_user
{"success":true,"message":"Saved a reset token for user1."}

... оба возвращают успех, как написано, но второе не влияет на поле БД "password_token".

Вот структурно идентичные экспресс-маршруты:

router.post('/save_hash', (req, res, next) => {
    const username = req.body.username;
    User.getUserByUsername(username, (err, user) => {
        if (err) logger.error(err);
        if (user) {
            bcrypt.hash(user.password, 10, (err, hash) => {
                if (hash) {
                    User.saveHash(user.username, hash, err);
                    return res.json({success: true, message: 'Saved a hash for ' + user.username + '.'});
                }
            })
        }
    })
});

router.post('/reset_user', (req, res, next) => {
    const username = req.body.username;
    User.getUserByUsername(username, (err, user) => {
        if (err) logger.error(err);
        if (user) {
            crypto.randomBytes(20, (err, buffer) => {
                if (buffer) {
                    const token = buffer.toString('hex');
                    User.resetToken(user.username, 'test', err);
                    if (err) {logger.error(err) } else {
                        return res.json({success: true, message: 'Saved a reset token for ' + user.username + '.'});
                    }
                }
            });
        }
    })
});

А вот структурно идентичные методы на моделях:

module.exports.saveHash = function (username, password_hash, callback) {
    const query = {'username': username};
    User.update(query, { $set: { 'password_hash': password_hash }}, (err_update, raw) => {
        if (err_update) { logger.error(err_update); } else {console.log('raw data: ', raw)}
    })
};

module.exports.resetToken = function (username, token, callback) {
    const query = {'username': username};
    User.update(query, { $set: { 'password_token': token}}, (err_update, raw) => {
        if (err_update) { logger.error(err_update); } else {console.log('raw data: ', raw)}
    })
};

Завиток, маршрут и модель для "password_hash" работают должным образом. То же самое дублирование для обновления «password_token» не работает. Даже следующие модификации работают:

module.exports.resetToken ...
User.update(query, { $set: { 'password_hash': token}}... // works. updates "password_hash" to the token value.

module.exports.resetToken ...
User.update(query, { $set: { 'password_hash': 'test'}}... // works. updates "password_hash" to 'test'.

... но если я изменю saveHash (), который в настоящее время работает для обновления «password_hash», так что вместо него должен быть «password_token», он не изменит «password_token»:

module.exports.saveHash ...
User.update(query, { $set: { 'password_token': 'test'}}... /* Does not work. returns  { ok: 0, n: 0, nModified: 0 } ...and does not modify "password_token". */

... Похоже, что с самим полем password_token что-то не так, поскольку я могу обновить другое поле с точно таким же кодом.

Для чего это стоит: вся документация, которую я прочитал, говорит, что я должен иметь возможность вызывать update () для поля, которое еще не существует, и оно будет создано неявным набором $ set, но я не обнаружил, что быть так. Мне пришлось создать оба «password_hash» и «password_token», используя MongoShell, прежде чем они могут быть обновлены:

db.users.update({},
  {$set : {"password_token":""}},
  {upsert:false,
  multi:true})

... так что мне интересно, могу ли я оказаться в адском варианте, и наконец я вижу симптом.

TL: DR; Я могу просто обновить одно поле «password_hash», но другое поле «password_token» (и любые дополнительные поля, которые я добавляю) не может быть обновлено и не возвращает ошибку, используя в основном тот же метод curl, route и model. Что дает?

1 Ответ

0 голосов
/ 28 августа 2018

Простой ответ, данный JohnnyHK, заключается в том, что новые поля, которые я создаю в БД, также не были определены в моей пользовательской схеме.

Я на самом деле уже делал эту же ошибку раньше. Отсутствие ошибки и единственная подсказка в том, что операция обновления не удалась, означает, что мне нужно завязывать строку вокруг моего пальца каждый раз, когда я добавляю новое поле в документ.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...