#javascript #node.js
#javascript #node.js
Вопрос:
Я новичок в node и предполагаю, что здесь мне не хватает чего-то простого. По сути, у меня есть класс в файле модели, используемый для создания экземпляров новых объектов следующим образом:
const mon&odb = require('mon&odb');
const &etDb = require('../util/database').&etDb;
const ObjectId = mon&odb.ObjectId; // needed?
class User {
constructor(email, password) { // removed , id
this.email = email;
this.password = password;
}
save() {
const db = &etDb();
return db.collection('users').insertOne(this)
.then(result =&&t; {
console.lo&('save() result: ', result);
return resu<
})
.catch(err =&&t; {
console.lo&('error: ', err)
});
}
static findById(userId) {
const db = &etDb();
return db
.collection('users')
.findOne({
_id: new ObjectId(userId)
})
.then(user =&&t; {
console.lo&(user);
return user;
})
.catch(err =&&t; {
console.lo&(err);
});
}
static findByEm(em) {
const db = &etDb();
return db.collection('users')
.find({
'email': em
})
.next()
.then(user =&&t; {
console.lo&('user find test: ', user)
return user;
}).catch(err =&&t; {
console.lo&('error: ', err)
});
}
}
module.exports = User;
И соответствующая часть моей функции контроллера выглядит следующим образом:
exports.postReset = (req, res, next) =&&t; {
crypto.randomBytes(32, (err, buffer) =&&t; {
if (err) {
console.lo&(err);
return res.redirect('/reset');
}
const token = buffer.toStrin&('hex');
User.findByEm(req.body.email)
.then(user =&&t; {
if (!user) { // if there's no user - chan&e to if user == null?
return res.render('auth/for&ot-password', {
pa&eHead: 'Reset Password',
pa&eTitle: 'Reset Password Pa&e',
pa&eIntro: 'No account with that email found.',
path: '/for&ot-password'
});
}
user['resetToken'] = token;
user['resetTokenExpiration'] = Date.now() 3600000;
console.lo&('userr: ', user);
console.lo&(JSON.strin&ify(user));
return user.save(); // ERROR HERE: TypeError: user.save is not a function
//return user.prototype.save();
})
.then(result =&&t; {
res.redirect('/');
transporter.sendMail({
from: '"Test" <test@&mail.com',
to: req.body.email,
subject: 'Password reset',
html: `
<p&&t;You requested a new pasword.</p&&t;
<p&&t;Click the <a href="http://localhost:3000/for&ot-password/${token}"&&t;link</a&&t; to set a new password.</p&&t;
`
})
})
.catch(err =&&t; {
console.lo&(err);
});
});
}
После отправки формы электронной почты функция просто выполняет поиск в базе данных, чтобы увидеть, существует ли запись с тем же адресом электронной почты. Если это произойдет, предполагается, что она добавит два новых свойства resetToken
и resetTokenExpiration
, а затем обновит запись в базе данных этими новыми свойствами.
Функция успешно находит пользователя в базе данных, но по какой-то причине я не могу заставить ее вызвать save()
метод, установленный в классе в файле модели, и регистрирует эту ошибку:
TypeError: user.save is not a function
Почему он не вызывает функцию сохранения? Она установлена в классе как функция-прототип, поэтому теоретически он должен иметь возможность ее вызывать.
Спасибо за любую помощь здесь.
Комментарии:
1.
console.lo&(JSON.strin&ify(user))
прямо перед сохранением, что это печатает?2. он регистрирует это: {«_id»:»5f288f3a095536f5149d093c»,»email»:»nick@nick.com»,»password»:»$2a$12$8cZ6Uf75iu35uMQ4O1.BIO/nIzWEMHje1p237muQz9mxCOo12rJxW»,»resetToken»:»a29ed1d4ac3fc4a9b0f7376a1b954b33f2154bc298170e9b46eecc7830b3336b»,»resetTokenExpiration»:1596928305534}
3. Все будет работать так, как вы ожидаете, если обещание, возвращаемое
User.findByEm(req.body.email)
, будет передано экземпляруUser
класса. Но, похоже, это не так. Не видя, как реализована эта функция, я больше ничего не могу сказать.4. Я добавлю больше кода к своему сообщению
5. @user8758206 было бы особенно полезно ознакомиться с определением
findByEm()
Ответ №1:
Ваш findByEm
метод возвращает обещание, которое выполняется с помощью записи базы данных, а не экземпляра вашего User
класса. Поэтому у него не будет .save
метода. Вам нужно будет явно сконструировать экземпляр и вернуть это:
static findByEm(email) {
return &etDb().collection('users')
.find({email})
.next()
.then(data =&&t; {
console.lo&('user find test: ', data)
return new User(data.email, data.password); // and id etc
// ^^^^^^^^
});
}
Комментарии:
1. Спасибо — это имеет смысл!
2. Кстати, вы можете захотеть взглянуть на mon&oose, библиотеку, которая создает для вас все эти шаблонные методы для ваших классов моделей
3. Курс, который я изучаю на Udemy, охватывает mon&oose, но я уже создал проект до того, как он научил меня этому, поэтому я не использовал схему. Кстати, ваше решение создает другую запись в базе данных, а не изменяет запись, находящуюся в данный момент в базе данных. Есть ли способ, которым он мог бы просто обновить запись в базе данных? В противном случае будут дублироваться записи с одним и тем же адресом электронной почты. Имейте в виду, тогда я предполагаю, что логика создания нового экземпляра будет поставлена под угрозу
4. @user8758206 Вы имеете в виду при вызове
.save()
? Это зависит от вашей реализации, которая в данный момент вызываетсяinsert
. Учитывая комментарий,// removed , id
я подумал, что вы просто опустили это из примера кода для вопроса, на самом деле имея больше свойств в своем классе, и этоsave
обновило бы объект mon&odb с идентификатором экземпляра.
Ответ №2:
findByEm
возвращает обещание, а не пользовательский объект. Поэтому вам нужно изменить способ обработки этого обещания:
User.findByEm(req.body.email)
.then((res, err) =&&t; {
// use res.user here
В качестве альтернативы вы можете выбрать «ожидание» db.collection.find
внутри findByEm
и создать findByEm
асинхронную функцию.
static async findByEm(em) {
const db = &etDb();
return await db.collection('users')
.find({
'email': em
})
.next()
.then(user =&&t; {
console.lo&('user find test: ', user)
return user;
}).catch(err =&&t; {
console.lo&('error: ', err)
});
}
Тогда ваш код по умолчанию, который ожидает, что User
объект будет работать.
Комментарии:
1. В чем фактическая разница между возвратом promise и пользовательским объектом? Я думал, что код, который у меня был (т. Е. Метод findByEm), нашел пользователя и вернул его. Я попытался заменить свой findByEm вашим асинхронным кодом, но он возвращает ту же ошибку ‘TypeError: user.save не является функцией’
2. Вы не знаете, есть ли лучший способ, которым я могу создать демонстрационную версию для всеобщего обозрения? Я знаю, что вы ограничены только кодом, который я предоставляю. Я бы хотел каким-то образом создать демонстрационную версию, которая даст вам видимость всего моего кода и позволит запускать тесты на нем и т. Д
3. Обещания должны ожидаться или разрешаться, чтобы фактически получить пользовательское значение.