[javascript] 몽구스에서 문서를 어떻게 업데이트 / 업데이트합니까?

아마도 그것은 아마도 시간 일 것입니다. 아마도 스파 스 문서에 빠져 익사하고 몽구스의 업데이트 개념에 대해 머리를 감쌀 수 없습니다 🙂

거래는 다음과 같습니다.

연락처 스키마 및 모델이 있습니다 (속성 단축).

var mongoose = require('mongoose'),
    Schema = mongoose.Schema;

var mongooseTypes = require("mongoose-types"),
    useTimestamps = mongooseTypes.useTimestamps;


var ContactSchema = new Schema({
    phone: {
        type: String,
        index: {
            unique: true,
            dropDups: true
        }
    },
    status: {
        type: String,
        lowercase: true,
        trim: true,
        default: 'on'
    }
});
ContactSchema.plugin(useTimestamps);
var Contact = mongoose.model('Contact', ContactSchema);

필요한 필드가 포함 된 클라이언트로부터 요청을 받고 모델을 다음과 같이 사용합니다.

mongoose.connect(connectionString);
var contact = new Contact({
    phone: request.phone,
    status: request.status
});

이제 우리는 문제에 도달합니다.

  1. 내가 전화하면 contact.save(function(err){...}) 같은 전화 번호를 가진 연락처가 이미 존재하는 경우 오류가 발생합니다 (예상대로-고유)
  2. 나는 전화 할 수 없다 update()해당 방법이 문서에 없기 때문에 연락
  3. 모델에서 업데이트를 호출하면 :
    Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
    하면 몽구스 업데이트 구현에서 객체를 두 번째 매개 변수로 원하지 않기 때문에 어떤 종류의 무한 루프에 빠지게됩니다.
  4. 내가 똑같이하지만 두 번째 매개 변수에서 요청 속성의 연관 배열을 전달하면 {status: request.status, phone: request.phone ...}작동하지만 특정 연락처에 대한 참조가 없으며 해당 속성 createdAtupdatedAt속성을 찾을 수 없습니다 .

결론적으로, 내가 시도한 모든 결론 : document가 주어지면 문서를 contact업데이트하거나 그렇지 않으면 어떻게 추가합니까?

시간 내 줘서 고마워.



답변

Mongoose는 이제 findOneAndUpdate를 통해이를 기본적으로 지원합니다 (MongoDB findAndModify 호출 ).

upsert = true 옵션은 객체가 존재하지 않는 경우 객체를 만듭니다. 기본값은 false 입니다.

var query = {'username': req.user.username};
req.newData.username = req.user.username;

MyModel.findOneAndUpdate(query, req.newData, {upsert: true}, function(err, doc) {
    if (err) return res.send(500, {error: err});
    return res.send('Succesfully saved.');
});

이전 버전에서 Mongoose는이 방법으로 이러한 후크를 지원하지 않습니다.

  • 기본값
  • 세터
  • 유효성 검사기
  • 미들웨어

답변

나는 같은 문제를 해결하기 위해 3 시간 동안 단단하게 태웠다. 특히, 전체 문서가있는 경우 “대체”하거나 그렇지 않으면 삽입하려고했습니다. 해결책은 다음과 같습니다.

var contact = new Contact({
  phone: request.phone,
  status: request.status
});

// Convert the Model instance to a simple object using Model's 'toObject' function
// to prevent weirdness like infinite looping...
var upsertData = contact.toObject();

// Delete the _id property, otherwise Mongo will return a "Mod on _id not allowed" error
delete upsertData._id;

// Do the upsert, which works like this: If no Contact document exists with 
// _id = contact.id, then create a new doc using upsertData.
// Otherwise, update the existing doc with upsertData
Contact.update({_id: contact.id}, upsertData, {upsert: true}, function(err{...});

Mongoose 프로젝트 페이지 에서 이에 대한 정보를 문서에 추가하도록 요청 하는 문제를 만들었습니다 .


답변

당신은 가까이했다

Contact.update({phone:request.phone}, contact, {upsert: true}, function(err){...})

그러나 두 번째 매개 변수는 수정 연산자가있는 객체 여야합니다.

Contact.update({phone:request.phone}, {$set: { phone: request.phone }}, {upsert: true}, function(err){...})


답변

글쎄, 나는 오래 기다렸고 대답이 없었다. 마지막으로 전체 업데이트 / 업로드 접근 방식을 포기하고 다음을 수행했습니다.

ContactSchema.findOne({phone: request.phone}, function(err, contact) {
    if(!err) {
        if(!contact) {
            contact = new ContactSchema();
            contact.phone = request.phone;
        }
        contact.status = request.status;
        contact.save(function(err) {
            if(!err) {
                console.log("contact " + contact.phone + " created at " + contact.createdAt + " updated at " + contact.updatedAt);
            }
            else {
                console.log("Error: could not save contact " + contact.phone);
            }
        });
    }
});

작동합니까? 네. 나는 이것으로 행복합니까? 아마 아닙니다. 하나 대신 2 개의 DB 호출.
바라건대 미래의 몽구스 구현에는 Model.upsert기능 이 생길 것입니다 .


답변

약속 체인을 사용하여 달성 할 수있는 매우 우아한 솔루션 :

app.put('url', (req, res) => {

    const modelId = req.body.model_id;
    const newName = req.body.name;

    MyModel.findById(modelId).then((model) => {
        return Object.assign(model, {name: newName});
    }).then((model) => {
        return model.save();
    }).then((updatedModel) => {
        res.json({
            msg: 'model updated',
            updatedModel
        });
    }).catch((err) => {
        res.send(err);
    });
});


답변

저는 몽구스의 관리자입니다. 문서를 upsert하는 더 현대적인 방법은 Model.updateOne()함수 를 사용하는 입니다.

await Contact.updateOne({
    phone: request.phone
}, { status: request.status }, { upsert: true });

혐의 된 의사가 필요한 경우 Model.findOneAndUpdate()

const doc = await Contact.findOneAndUpdate({
    phone: request.phone
}, { status: request.status }, { upsert: true });

중요한 점은 filter매개 변수 의 고유 속성 을 updateOne()또는에 findOneAndUpdate(), 다른 속성을 매개 변수 에 넣어야한다는 것 update입니다.

다음 은 Mongoose로 문서업데이트 하는 방법에 대한 자습서입니다 .


답변

이 질문에 대답하기 위해 StackOverflow 계정 JUST을 만들었습니다. 과일없이 웹을 검색 한 후 나는 방금 뭔가를 썼습니다. 이것이 내가 그렇게 한 방법이므로 모든 몽구스 모델에 적용 할 수 있습니다. 이 함수를 가져 오거나 업데이트중인 코드에 직접 추가하십시오.

function upsertObject (src, dest) {

  function recursiveFunc (src, dest) {
    _.forOwn(src, function (value, key) {
      if(_.isObject(value) && _.keys(value).length !== 0) {
        dest[key] = dest[key] || {};
        recursiveFunc(src[key], dest[key])
      } else if (_.isArray(src) && !_.isObject(src[key])) {
          dest.set(key, value);
      } else {
        dest[key] = value;
      }
    });
  }

  recursiveFunc(src, dest);

  return dest;
}

그런 다음 몽구스 문서를 업데이트하려면 다음을 수행하십시오.

YourModel.upsert = function (id, newData, callBack) {
  this.findById(id, function (err, oldData) {
    if(err) {
      callBack(err);
    } else {
      upsertObject(newData, oldData).save(callBack);
    }
  });
};

이 솔루션에는 2 회의 DB 호출이 필요할 수 있지만 다음과 같은 이점이 있습니다.

  • .save ()를 사용하고 있으므로 모델에 대한 스키마 유효성 검사
  • 업데이트 호출에서 수동 열거없이 깊게 중첩 된 객체를 업 사트 할 수 있으므로 모델 변경시 코드 업데이트에 대해 걱정할 필요가 없습니다.

소스에 기존 값이 있더라도 대상 객체는 항상 소스를 재정의합니다.

또한 배열의 경우 기존 개체가 대체하는 것보다 긴 배열을 갖는 경우 이전 배열의 끝에있는 값이 유지됩니다. 전체 배열을 upsert하는 쉬운 방법은 이전 배열을 upsert 전에 빈 배열로 설정하는 것입니다.

업데이트-2016 년 1 월 16 일 기본 값 배열이있는 경우 추가 조건을 추가했지만 몽구스는 “set”기능을 사용하지 않고 배열이 업데이트되는 것을 인식하지 못합니다.