Подтвердить что ты не робот

NodeJS + Mongoose: обновление всех полей модели Mongoose

Я создаю api, используя Node, MongoDB и Mongoose. Меня беспокоит то, что вы не можете сразу установить несколько полей:

app.put('/record/:id', function(req, res) {
  Record.findById(req.params.id, function(err, doc) {
    if (!err) {
      doc.update(req.params);
      doc.save();
...

Однако, похоже, что вам нужно разработать запрос на обновление и запустить его на объекте Model, а не на объекте документа. Если вы не хотите назначать отдельные свойства и запускать save() в конце.

Есть ли способ выполнить это без необходимости писать запрос Mongo?

4b9b3361

Ответ 1

Ответ jsaak хорош, но не работает для вложенных объектов. Я разработал его ответ, выполнив поиск и установив вложенные объекты.

Я добавил эти функции в файл utility.js

var _ = require('underscore');

exports.updateDocument = function(doc, SchemaTarget, data) {
    for (var field in SchemaTarget.schema.paths) {
       if ((field !== '_id') && (field !== '__v')) {
            var newValue = getObjValue(field, data);
            console.log('data[' + field + '] = ' + newValue);
            if (newValue !== undefined) {
                setObjValue(field, doc, newValue);
          }  
       }  
    }
    return doc;
};

function getObjValue(field, data) {
    return _.reduce(field.split("."), function(obj, f) { 
        if(obj) return obj[f];
    }, data);
}

function setObjValue(field, data, value) {
  var fieldArr = field.split('.');
  return _.reduce(fieldArr, function(o, f, i) {
     if(i == fieldArr.length-1) {
          o[f] = value;
     } else {
          if(!o[f]) o[f] = {};
     }
     return o[f];
  }, data);
}

реализовать как:

var util = require('./utility');

app.put('/record/:id', function(req, res) {
  Record.findById(req.params.id, function(err, doc) {
    if (!err) {
      utils.updateDocument(doc, Record, req.params);
      doc.save();
    ...

Ответ 2

Возможно, это изменилось с тех пор, как этот вопрос был задан первым, но вы можете обновлять несколько путей в Mongoose с помощью метода set ike:

// object
doc.set({
  path  : value,
  path2 : {
    path  : value
  }
});
doc.save();

Ссылки

Ответ 3

прямое обновление не рекомендуется в соответствии с этим документом: http://mongoosejs.com/docs/2.7.x/docs/updating-documents.html

я решил это следующим образом:

  Book.findOne({isbn: req.params.isbn}, function (err, book){
     if (err) {
        res.send(422,'update failed');
     } else {
        //update fields
        for (var field in Book.schema.paths) {
           if ((field !== '_id') && (field !== '__v')) {
              if (req.body[field] !== undefined) {
                 book[field] = req.body[field];
              }  
           }  
        }  
        book.save();
     }
  });

Ответ 4

Если вы хотите обновить весь документ, вы можете удалить документ на основе его идентификатора и снова сохранить весь объект. Этот объект должен содержать данные для каждого поля документа mongo.

Вот пример.

mongoDBCollectionObject.findOneAndRemove({ // -- it will delete the entire document
  _id: req.body.fieldsdata._id  // here fiedsdata is exact copy with modification  of previous data
  }, function(err, data) {
  var newFieldsData = new mongoDBCollectionObject(fieldsdata); //-- fieldsdata updated data
  newFieldsData.save(function(err, data) { // save document to that collection with updated data
    if (err) {
      console.log(err);
    } else
        res.json({
          success: true
          });
    });
  })

Ответ 5

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

Есть ли способ выполнить это без необходимости писать запрос Mongo?

Очевидным ответом является обновление объекта Model со значением из запроса. Это то, что вы предлагаете...

Если вы не хотите назначать отдельные свойства и запускать save() в конце.

Но похоже, что вы не хотите этого делать? Похоже, вы хотите обновить объект Model непосредственно из объекта Request?

Вы можете сделать это, если хотите. Вы просто проходите через req.params и устанавливаете значения doc, где это необходимо.

for(var i in req.params) {
  if(req.params[i] != doc[i]){
    doc[i] = req.params[i];
  }
}

Это должно быть так просто. Однако вы хотите сделать это, только если у вас есть целая куча кода проверки на объектах модели. Весь смысл модели заключается в том, что вы не хотите получать случайные данные в БД. Вышеуказанная строка в целом "установит" правильные значения, но вам обязательно нужно включить код для аутентификации, авторизации и проверки вокруг этого простого цикла for.

Ответ 6

попробуйте обновить коллекцию без поиска, например

Record.update({_id:req.params.id}, {$set: { field: request.field }}, {upsert: true}, function(err{...})

Опция upsert создает документ, если он не существует.

Ответ 7

Если у вас есть новый объект и вы хотите обновить весь объект в базе данных, вы можете обновить сразу несколько полей следующим образом:

  • найти объект
  • получить все пути схемы (поля)
  • сохранить новый объект.

SomeModel.findOne({ 'id': 'yourid' },function (err, oldObject) {
	if (err) return handleError(err);

	// get all schema paths (fields)
	SomeModel.schema.eachPath(function(path) {

	    // leave __id and __v alone
	    if (path != '_id' && path != '__v') {
	    	// update the data from new object
	    	oldObject[path] = newObject[path];
	    }
	})

	oldObject.save(function(err) {
		if (err)
		console.log(err)
	});
})

Ответ 8

Аккуратный и чистый подход будет использовать async await и findOneAndRemove вместе с create Вот пример кода

try {
            let resp = await this.findOneAndRemove({ _id: req.body._id });
            let entry = await this.create(req.body);

    } catch (err) {

    }

Не забудьте пометить всю эту функцию как async