#node.js #mongodb #express #mongoose
#node.js #mongodb #экспресс #mongoose
Вопрос:
Когда я обновляю свой профиль пользователя, удаляются окрестности поля, которое находится внутри location в моей пользовательской модели, это моя пользовательская модель, где вы можете видеть окрестности внутри location:
const userSchema = new Schema({
name: {
type: String,
required: 'Please supply a name',
trim: true
},
location: {
type: {
type: String,
default: 'Point'
},
coordinates: [{
type: Number,
required: 'You must supply coordinates!'
}],
address: {
type: String,
required: 'You must supply an address!'
},
vicinity: {
type: String,
},
},
});
Затем у меня есть контроллер, который обновляет пользователя, где у меня есть объект updates, и окрестности нет, так как я не хочу его обновлять, я просто хочу сохранить окрестности в реестре, а не обновлять его:
exports.updateAccount = async (req, res) => {
req.body.location.type = 'Point';
const updates = {
email: req.body.email,
name: req.body.name,
photo: req.body.photo,
genres: req.body.genres,
musicLinks: req.body.musicLinks,
location: {
type: req.body.location.type,
coordinates: [
req.body.location.coordinates[0],
req.body.location.coordinates[1],
],
address: req.body.location.address,
// vicinity: req.body.location.vicinity,
}
};
if(!updates.photo) delete updates.photo
const user = await User.findOneAndUpdate(
{ _id: req.user._id },
{ $set: updates },
{ new: true, runValidators: true, context: 'query' }
);
req.flash('success', 'Updated the profile!');
res.redirect('back');
};
Но каждый раз, когда я обновляю профиль пользователя, поле близости стирается, также обратите внимание, что в форме, в которой я отправляю обновление для пользователя, нет поля для близости, поэтому он не отправляет никаких данных для обновления.
Я предполагаю, что, поскольку на контроллере у меня есть объект обновлений, подобный:
location: {
type: req.body.location.type,
coordinates: [
req.body.location.coordinates[0],
req.body.location.coordinates[1],
],
address: req.body.location.address,
// vicinity: req.body.location.vicinity,
}
и ее отсутствующий vecinity. база данных пытается сохранить весь объект location, и поскольку поблизости нет, он стирается.
Если это так .. как мне сказать mongo db, чтобы сохранить значение в базе данных и не удалять его? Спасибо
Ответ №1:
Причина, по которой у вас это происходит, заключается в том, что вы фактически обновляете location
поле новым объектом. Каждый ключ под location
объектом стирается, а затем перезаписывается — вот почему vicinity
теряется.
Для достижения вашей цели вы можете использовать синтаксис вложенного ключа:
const updates = {
$set: {
email: req.body.email,
name: req.body.name,
photo: req.body.photo,
genres: req.body.genres,
musicLinks: req.body.musicLinks,
'location.type': req.body.location.type,
'location.coordinates': [req.body.location.coordinates[0], req.body.location.coordinates[1]],
'location.address': req.body.location.address,
}
};
После этого:
const user = await User.findOneAndUpdate(
{ _id: req.user._id },
updates,
{ new: true, runValidators: true, context: 'query' }
);
Ответ №2:
Это специально.
На самом деле вы включаете «полный объект» для location
в свои аргументы для $set
, и это просто перезаписывает этот объект. В принципе, так работает MongoDB.
Другая часть работы MongoDB заключается в том, что когда вы намереваетесь частично обновить документ с помощью «вложенных путей», вам нужно обработать эту структуру объекта в форме «точечной нотации».
На самом деле, вот базовая версия того, что я собрал давным-давно, чтобы сделать именно это:
var data = {
email: "bill@example.com",
name: "Bill S Preston",
photo: "",
genres: "Music, Lyrics",
musicLinks: "",
location: {
type: "Point",
coordinates: [
0,
0
],
address: "somewhere"
}
};
И простая функция:
function dotNotate(obj,target,prefix) {
target = target || {},
prefix = prefix || "";
Object.keys(obj).forEach(function(key) {
if ( Array.isArray(obj[key] )) {
return target[prefix key] = obj[key];
} else if ( typeof(obj[key]) === "object" ) {
dotNotate(obj[key],target,prefix key ".");
} else {
return target[prefix key] = obj[key];
}
});
return target;
}
Запуск этой функции приводит к:
var updates = dotNotate(data);
{
"email" : "bill@example.com",
"name" : "Bill S Preston",
"photo" : "",
"genres" : "Music, Lyrics",
"musicLinks" : "",
"location.type" : "Point",
"location.coordinates" : [
0,
0
],
"location.address" : "somewhere"
}
И, конечно, { $set: updates }
только частично обновит явно указанные поля без перезаписи.
Комментарии:
1. Как мне использовать вашу функцию? Я предполагаю, что obj — это данные .. но что я должен указать в параметрах target и prefix? Большое спасибо! 🙂
2. @GiorgioMartini Вам не нужно этого делать, если вы специально не хотели этого (т. Е. вложить в другой объект). Для вашего использования в соответствии с примером, показанным в ответе, просто необходимо предоставить весь объект из запроса, который вы в данный момент извлекаете. Эти дополнительные аргументы функции в основном присутствуют там, потому что она рекурсивна и работает на нескольких глубинах.