아마도 그것은 아마도 시간 일 것입니다. 아마도 스파 스 문서에 빠져 익사하고 몽구스의 업데이트 개념에 대해 머리를 감쌀 수 없습니다 🙂
거래는 다음과 같습니다.
연락처 스키마 및 모델이 있습니다 (속성 단축).
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
});
이제 우리는 문제에 도달합니다.
- 내가 전화하면
contact.save(function(err){...})
같은 전화 번호를 가진 연락처가 이미 존재하는 경우 오류가 발생합니다 (예상대로-고유) - 나는 전화 할 수 없다
update()
해당 방법이 문서에 없기 때문에 연락 - 모델에서 업데이트를 호출하면 :
Contact.update({phone:request.phone}, contact, {upsert: true}, function(err{...})
하면 몽구스 업데이트 구현에서 객체를 두 번째 매개 변수로 원하지 않기 때문에 어떤 종류의 무한 루프에 빠지게됩니다. - 내가 똑같이하지만 두 번째 매개 변수에서 요청 속성의 연관 배열을 전달하면
{status: request.status, phone: request.phone ...}
작동하지만 특정 연락처에 대한 참조가 없으며 해당 속성createdAt
과updatedAt
속성을 찾을 수 없습니다 .
결론적으로, 내가 시도한 모든 결론 : 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”기능을 사용하지 않고 배열이 업데이트되는 것을 인식하지 못합니다.