programing

Mongoose와 함께 대량 상승을 시도하고 있습니다.가장 깨끗한 방법은 무엇입니까?

padding 2023. 7. 17. 20:43
반응형

Mongoose와 함께 대량 상승을 시도하고 있습니다.가장 깨끗한 방법은 무엇입니까?

first_name, last_name 및 age의 세 가지 필드가 포함된 문서를 보관하는 컬렉션이 있습니다.Mongoose에서 대량 업셋을 수행하는 데 사용할 수 있는 쿼리를 찾고 있습니다.내 앱은 때때로 동일한 세 개의 필드를 가진 새로운 객체 배열을 수신합니다.문서에 이름과 성이 이미 존재하는지, 존재하는지, 존재하는지 여부를 쿼리에서 확인하고, 다른 경우 기간을 업데이트합니다.그렇지 않은 경우, 이름과 성이 없는 경우, 새 문서를 삽입합니다.

현재, 저는 가져오기만 하고 있으며, 이 비정상적인 작품에 대한 논리를 아직 구축하지 못했습니다.

app.post('/users/import', function(req, res) {
  let data = req.body;
  let dataArray = [];
  data.forEach(datum => {
    dataArray.push({
        first: datum.first,
        last: datum.last,
        age: datum.age
    })
})

User.insertMany(dataArray, answer => {
    console.log(`Data Inserted:`,answer)
})

`

제 사용자 모델은 다음과 같습니다.

const mongoose = require('mongoose');

const Schema = mongoose.Schema;

const userSchema = new Schema({
  first: String,
  last: String,
  age: Number,
  created_at: { type: Date, default: Date.now }
});

var User = mongoose.model('User', userSchema);
module.exports = User;

(mongoose@4.9.1, mongodb@3.4.2)

TL;DR

await GasStation.collection.bulkWrite([ // <<==== use the model name
  {
    'updateOne': {
      'filter': { 'id': '<some id>' },
      'update': { '$set': { /* properties to update */ } },
      'upsert': true,  // <<==== upsert in every document
    }
  },
  /* other operations here... */
]);

긴 이야기:

Mongoose API 문서 불량으로 어려움을 겪은 후 대량 업셋 수정을 해결했습니다.updateOne:{}에 있어서의 작전.bulkWrite()방법.

고려해야 할 문서화되지 않은 몇 가지 사항:

// suppose:
var GasStation = mongoose.model('gasstation', gasStationsSchema);
var bulkOps = [ ];

// for ( ... each gasStation to upsert ...) {
  let gasStation = { country:'a', localId:'b', xyz:'c' };
  // [populate gasStation as needed]
  // Each document should look like this: (note the 'upsert': true)
  let upsertDoc = {
    'updateOne': {
      'filter': { 'country': gasStation.country, 'localId': gasStation.localId },
      'update': gasStation,
      'upsert': true
  }};
  bulkOps.push(upsertDoc);
// end for loop

// now bulkWrite (note the use of 'Model.collection')
GasStation.collection.bulkWrite(bulkOps)
  .then( bulkWriteOpResult => {
    console.log('BULK update OK');
    console.log(JSON.stringify(bulkWriteOpResult, null, 2));
  })
  .catch( err => {
    console.log('BULK update error');
    console.log(JSON.stringify(err, null, 2));
  });

여기서 두 가지 핵심 사항은 불완전한 API 문서 문제입니다(적어도 작성 시점에서는).

  • 'upsert': true 각 서류에이 문제는 Mongoose API()에는 설명되어 있지 않습니다. Mongoose API는 종종 노드-mongodb 네이티브 드라이버를 가리킵니다.업데이트를 보면드라이버에서 하나를 추가할 수 있습니다.'options':{'upsert': true}하지만, 아니...그것으로는 안 됩니다.저는 또한 두 가지 사례를 추가하려고 했습니다.bulkWrite(,[options],)인수도 효과가 없습니다.
  • GasStation.collection.bulkWrite()Mongoose bulkWrite() 메서드가 호출되어야 한다고 주장하지만Model.bulkWrite()(이 경우에는,GasStation.bulkWrite()), 트리거합니다.MongoError: Unknown modifier: $__.그렇게,Model.collection.bulkWrite()사용해야 합니다.

추가로, 참고:

  • 사용할 필요가 없습니다.$set의 몽고 연산자updateOne.update필드, mongoose는 업버트 시 처리하기 때문입니다(: bulkWrite() 주석 참조).
  • 스키마의 고유 인덱스(업그레이드를 위해 필요함)는 다음과 같이 정의됩니다.

gasStationsSchema.index({ country: 1, localId: 1 }, { unique: true });

도움이 되길 바랍니다.

==> EDIT : (몽구스5?)

@Justin Smith가 주목했듯이,$setMongoose가 추가한 연산자는 더 이상 작동하지 않는 것 같습니다.Mongoose 5 때문인가요?

어떤 경우에도, 사용$set다음을 수행해야 합니다.

'update': { '$set': gasStation },

@maganap 감사합니다.저는 그/그녀의 답변을 이용하여 아래와 같은 간결한 접근법에 도달했습니다.

await Model.bulkWrite(docs.map(doc => ({
    updateOne: {
        filter: {id: doc.id},
        update: doc,
        upsert: true,
    }
})))


또는 자세한 내용:

const bulkOps = docs.map(doc => ({
    updateOne: {
        filter: {id: doc.id},
        update: doc,
        upsert: true,
    }
}))

Model.bulkWrite(bulkOps)
        .then(console.log.bind(console, 'BULK update OK:', bulkWriteOpResult))
        .catch(console.error.bind(console, 'BULK update error:'))

Mongoose용으로 정적을 노출하는 작은 플러그인을 릴리스했습니다.upsertMany약속 인터페이스를 사용하여 대량 업버트 작업을 수행하는 방법입니다.이를 통해 스키마 유효성 검사 등을 유지하면서 Mongoose를 사용하여 대량 업그레이드를 수행하는 매우 깨끗한 방법을 제공할 수 있습니다.

MyModel.upsertMany(items, ['matchField', 'other.nestedMatchField']);

이 플러그인은 npm 또는 Github에서 찾을 수 있습니다.

https://github.com/meanie/mongoose-upsert-many https://www.npmjs.com/package/ @mongoose-upert-many

위의 @magnap 솔루션을 사용해보니 단순히 업데이트하고 싶었던 기존 문서를 덮어쓰는 것이었습니다.에서 설정한 updates.updateOne 필드를 에 지정된 로 대체하는 이었습니다..update.

저는 결국 사용해야 했습니다.$set이 문제를 해결하기 위한 업데이트 방법입니다.과 같이 표시되었습니다.

const { ObjectId } = require('mongodb');

exports.bulkUpsert = (req, res, next) => {
     const { updates } = req.body;
     const bulkOps = updates.map(update => ({
         updateOne: {
             filter: { _id: ObjectId(update.id) },
             // Where field is the field you want to update
             update: { $set: { field: update.field } },
             upsert: true
          }
      }));
    // where Model is the name of your model
    return Model.collection
        .bulkWrite(bulkOps)
        .then(results => res.json(results))
        .catch(err => next(err));
};

이는 Mongoose 5.1.2와 함께 작동합니다.

사용할 수 있습니다.array.map대신에 사용합니다.for

 const result = await Model.bulkWrite(
    documents.map(document => {

        document = {
          ...document, 
          ...{
            last_update: Date.now(),
            foo: 'bar'
          }
        }

        return {
          updateOne: {
            filter: { document_id: document.document_id }, //filter for each item
            update: {
              $set: document,//update whole document
              $inc: { version: 1 }//increase version + 1
            },
            upsert: true //upsert document
          }
        }

      }
    ));

여기 제 답변이 도움이 되길 바랍니다.비동기식으로 e커머스 도메인에 대한 대량 업버트를 처리합니다.

공식 솔루션 찾기: https://docs.mongodb.com/manual/reference/method/Bulk.find.upsert/

그리고 몽구스도 같은 사슬을 지지합니다.

Bulk.find(<query>).upsert().update(<update>);
Bulk.find(<query>).upsert().updateOne(<update>);
Bulk.find(<query>).upsert().replaceOne(<replacement>);

작동 테스트:

BulkWriteResult {
  result:
   { ok: 1,
     writeErrors: [],
     writeConcernErrors: [],
     insertedIds: [],
     nInserted: 0,
     nUpserted: 1,
     nMatched: 4186,
     nModified: 0,
     nRemoved: 0,
     upserted: [ [Object] ] } }

이것을 확인하세요. 이것이 당신에게 충분히 도움이 되기를 바랍니다. 링크

링크2

제 생각에 당신은 찾고 있는 것 같습니다.

Bulk.find().upsert().update()

당신은 이것을 사용할 수 있습니다.

bulk = db.yourCollection.initializeUnorderedBulkOp();
for (<your for statement>) {
    bulk.find({ID: <your id>, HASH: <your hash>}).upsert().update({<your update fields>});
}
bulk.execute(<your callback>)
  • 문서를 찾으면 {}을(를) 사용하여 해당 문서를 업데이트합니다.
  • 그렇지 않으면 새 문서가 만들어집니다.

언급URL : https://stackoverflow.com/questions/39988848/trying-to-do-a-bulk-upsert-with-mongoose-whats-the-cleanest-way-to-do-this

반응형