При обновлении профиля пользователя некоторая информация стирается из базы данных, Mongodb

#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 Вам не нужно этого делать, если вы специально не хотели этого (т. Е. вложить в другой объект). Для вашего использования в соответствии с примером, показанным в ответе, просто необходимо предоставить весь объект из запроса, который вы в данный момент извлекаете. Эти дополнительные аргументы функции в основном присутствуют там, потому что она рекурсивна и работает на нескольких глубинах.