Programing

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

lottogame 2020. 3. 6. 08:18
반응형

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


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

거래는 다음과 같습니다.

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

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);
    });
});

이 질문에 대답하기 위해 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"기능을 사용하지 않고 배열이 업데이트되는 것을 인식하지 못합니다.


문서를 하나의 컬렉션으로 업데이트 / 업데이트해야했습니다. 내가 한 일은 다음과 같이 새 객체 리터럴을 만드는 것입니다.

notificationObject = {
    user_id: user.user_id,
    feed: {
        feed_id: feed.feed_id,
        channel_id: feed.channel_id,
        feed_title: ''
    }
};

데이터베이스의 다른 곳에서 얻은 데이터로 구성된 다음 모델에서 업데이트를 호출합니다.

Notification.update(notificationObject, notificationObject, {upsert: true}, function(err, num, n){
    if(err){
        throw err;
    }
    console.log(num, n);
});

이것은 스크립트를 처음 실행 한 후에 얻는 출력입니다.

1 { updatedExisting: false,
    upserted: 5289267a861b659b6a00c638,
    n: 1,
    connectionId: 11,
    err: null,
    ok: 1 }

그리고 이것은 스크립트를 두 번째로 실행할 때의 결과입니다.

1 { updatedExisting: true, n: 1, connectionId: 18, err: null, ok: 1 }

몽구스 버전 3.6.16을 사용하고 있습니다.


app.put('url', function(req, res) {

        // use our bear model to find the bear we want
        Bear.findById(req.params.bear_id, function(err, bear) {

            if (err)
                res.send(err);

            bear.name = req.body.name;  // update the bears info

            // save the bear
            bear.save(function(err) {
                if (err)
                    res.send(err);

                res.json({ message: 'Bear updated!' });
            });

        });
    });

몽구스에서 업데이트 방법을 해결하는 더 좋은 방법은 다음과 같습니다 . 자세한 내용은 Scotch.io확인 하십시오. 이것은 확실히 나를 위해 일했다! !!


2.6에서 소개 된 버그가 있으며 2.7에도 영향을줍니다.

2.4에서 올바르게 작동하는 데 사용되는 upsert

https://groups.google.com/forum/#!topic/mongodb-user/UcKvx4p4hnY https://jira.mongodb.org/browse/SERVER-13843

살펴보면 중요한 정보가 들어 있습니다.

업데이트 :

upsert가 작동하지 않는다는 의미는 아닙니다. 사용 방법에 대한 좋은 예는 다음과 같습니다.

User.findByIdAndUpdate(userId, {online: true, $setOnInsert: {username: username, friends: []}}, {upsert: true})
    .populate('friends')
    .exec(function (err, user) {
        if (err) throw err;
        console.log(user);

        // Emit load event

        socket.emit('load', user);
    });

당신은 단순히 이것으로 레코드를 업데이트하고 응답으로 업데이트 된 데이터를 얻을 수 있습니다

router.patch('/:id', (req, res, next) => {
    const id = req.params.id;
    Product.findByIdAndUpdate(id, req.body, {
            new: true
        },
        function(err, model) {
            if (!err) {
                res.status(201).json({
                    data: model
                });
            } else {
                res.status(500).json({
                    message: "not found any relative data"
                })
            }
        });
});

이것은 나를 위해 일했습니다.

app.put('/student/:id', (req, res) => {
    Student.findByIdAndUpdate(req.params.id, req.body, (err, user) => {
        if (err) {
            return res
                .status(500)
                .send({error: "unsuccessful"})
        };
        res.send({success: "success"});
    });

});


ContactSchema.connection.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 호출이 필요하지만 단일 호출에서 시도한 것보다 훨씬 안정적입니다.

// Create or update a Person by unique email.
// @param person - a new or existing Person
function savePerson(person, done) {
  var fieldsToUpdate = ['name', 'phone', 'address'];

  Person.findOne({
    email: person.email
  }, function(err, toUpdate) {
    if (err) {
      done(err);
    }

    if (toUpdate) {
      // Mongoose object have extra properties, we can either omit those props
      // or specify which ones we want to update.  I chose to update the ones I know exist
      // to avoid breaking things if Mongoose objects change in the future.
      _.merge(toUpdate, _.pick(person, fieldsToUpdate));
    } else {      
      toUpdate = person;
    }

    toUpdate.save(function(err, updated, numberAffected) {
      if (err) {
        done(err);
      }

      done(null, updated, numberAffected);
    });
  });
}

다음은 미들웨어 및 유효성 검증기를 호출하면서 작성 / 업데이트하는 가장 간단한 방법입니다.

Contact.findOne({ phone: request.phone }, (err, doc) => {
    const contact = (doc) ? doc.set(request) : new Contact(request);

    contact.save((saveErr, savedContact) => {
        if (saveErr) throw saveErr;
        console.log(savedContact);
    });
})

//Here is my code to it... work like ninj

router.param('contractor', function(req, res, next, id) {
  var query = Contractors.findById(id);

  query.exec(function (err, contractor){
    if (err) { return next(err); }
    if (!contractor) { return next(new Error("can't find contractor")); }

    req.contractor = contractor;
    return next();
  });
});

router.get('/contractors/:contractor/save', function(req, res, next) {

    contractor = req.contractor ;
    contractor.update({'_id':contractor._id},{upsert: true},function(err,contractor){
       if(err){ 
            res.json(err);
            return next(); 
            }
    return res.json(contractor); 
  });
});


--

발전기를 사용할 수 있다면 더욱 쉬워집니다.

var query = {'username':this.req.user.username};
this.req.newData.username = this.req.user.username;
this.body = yield MyModel.findOneAndUpdate(query, this.req.newData).exec();

다음 기술 가이 여행 이미 최고, 우리는 플러그인을 작성하고 우리가 그것을 초기화하면 그 있도록 몽구스에 첨부 할 수의 대답, .upsert()모든 모델에 사용할 수 있습니다.

plugins.js

export default (schema, options) => {
  schema.statics.upsert = async function(query, data) {
    let record = await this.findOne(query)
    if (!record) {
      record = new this(data)
    } else {
      Object.keys(data).forEach(k => {
        record[k] = data[k]
      })
    }
    return await record.save()
  }
}

db.js

import mongoose from 'mongoose'

import Plugins from './plugins'

mongoose.connect({ ... })
mongoose.plugin(Plugins)

export default mongoose

그런 다음 원하는 때나 원하는 때에 무엇 User.upsert({ _id: 1 }, { foo: 'bar' })이든 YouModel.upsert({ bar: 'foo' }, { value: 1 })할 수 있습니다.


잠시 후이 문제로 돌아와서 Aaron Mast의 답변에 따라 플러그인을 게시하기로 결정했습니다.

https://www.npmjs.com/package/mongoose-recursive-upsert

몽구스 플러그인으로 사용하십시오. 전달 된 객체를 재귀 적으로 병합하는 정적 메소드를 설정합니다.

Model.upsert({unique: 'value'}, updateObject});

User.findByIdAndUpdate(req.param('userId'), req.body, (err, user) => {
    if(err) return res.json(err);

    res.json({ success: true });
});

다른 해결책은 나를 위해 일하지 않았습니다. 게시 요청을 사용하고 데이터를 삽입하면 데이터를 업데이트하고 _id도 제거 해야하는 요청 본문과 함께 전송됩니다.

router.post('/user/createOrUpdate', function(req,res){
    var request_data = req.body;
    var userModel = new User(request_data);
    var upsertData = userModel.toObject();
    delete upsertData._id;

    var currentUserId;
    if (request_data._id || request_data._id !== '') {
        currentUserId = new mongoose.mongo.ObjectId(request_data._id);
    } else {
        currentUserId = new mongoose.mongo.ObjectId();
    }

    User.update({_id: currentUserId}, upsertData, {upsert: true},
        function (err) {
            if (err) throw err;
        }
    );
    res.redirect('/home');

});

이 커피 스크립트는 Node와 함께 작동합니다. 트릭은 클라이언트에서 보내고 반환 할 때 _id가 ObjectID 래퍼를 제거하므로 업데이트를 위해 교체해야합니다 (_id가 제공되지 않은 경우 저장은 삽입 및 추가로 되돌아갑니다) 하나).

app.post '/new', (req, res) ->
    # post data becomes .query
    data = req.query
    coll = db.collection 'restos'
    data._id = ObjectID(data._id) if data._id

    coll.save data, {safe:true}, (err, result) ->
        console.log("error: "+err) if err
        return res.send 500, err if err

        console.log(result)
        return res.send 200, JSON.stringify result

Martin Kuzdowicz가 위에 게시 한 내용을 기반으로합니다. 몽구스와 json 객체의 깊은 병합을 사용하여 업데이트를 수행하려면 다음을 사용하십시오. mongoose의 model.save () 함수와 함께 mongoose는 json의 다른 값에 의존하는 전체 검증을 수행 할 수 있습니다. deepmerge 패키지 https://www.npmjs.com/package/deepmerge 가 필요합니다 . 그러나 이것은 매우 가벼운 패키지입니다.

var merge = require('deepmerge');

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

    const modelId = req.body.model_id;

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

위의 게시물을 읽은 후이 코드를 사용하기로 결정했습니다.

    itemModel.findOne({'pid':obj.pid},function(e,r){
        if(r!=null)
        {
             itemModel.update({'pid':obj.pid},obj,{upsert:true},cb);
        }
        else
        {
            var item=new itemModel(obj);
            item.save(cb);
        }
    });

r이 null이면 새 항목을 만듭니다. 그렇지 않으면 업데이트시 새 항목이 생성되지 않으므로 upsert를 업데이트에 사용하십시오.

참고 URL : https://stackoverflow.com/questions/7267102/how-do-i-update-upsert-a-document-in-mongoose



반응형